jscmd 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +56 -0
 - data/GPL +340 -0
 - data/History.txt +7 -0
 - data/Manifest.txt +16 -0
 - data/README.txt +6 -0
 - data/Rakefile +89 -0
 - data/bin/jscmd +44 -0
 - data/lib/jscmd.rb +1 -0
 - data/lib/jscmd/agent.js +253 -0
 - data/lib/jscmd/asynchttpproxy.rb +140 -0
 - data/lib/jscmd/jscommander.rb +339 -0
 - data/lib/jscmd/version.rb +9 -0
 - data/scripts/txt2html +67 -0
 - data/setup.rb +1585 -0
 - data/test/test_helper.rb +2 -0
 - data/test/test_jscmd.rb +94 -0
 - metadata +62 -0
 
    
        data/bin/jscmd
    ADDED
    
    | 
         @@ -0,0 +1,44 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #! /opt/local/bin/ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            begin
         
     | 
| 
      
 4 
     | 
    
         
            +
              require 'rubygems'
         
     | 
| 
      
 5 
     | 
    
         
            +
            rescue LoadError
         
     | 
| 
      
 6 
     | 
    
         
            +
              # no rubygems to load, so we fail silently
         
     | 
| 
      
 7 
     | 
    
         
            +
            end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            if File.exist?(File.dirname(__FILE__) + "/../lib/jscmd.rb")
         
     | 
| 
      
 10 
     | 
    
         
            +
              $LOAD_PATH.unshift File.dirname(__FILE__) + "/../lib"
         
     | 
| 
      
 11 
     | 
    
         
            +
            end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            require 'jscmd'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require 'optparse'
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
            OPTIONS = {
         
     | 
| 
      
 17 
     | 
    
         
            +
              :port     => 9000
         
     | 
| 
      
 18 
     | 
    
         
            +
            }
         
     | 
| 
      
 19 
     | 
    
         
            +
            MANDATORY_OPTIONS = %w()
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            parser = OptionParser.new do |opts|
         
     | 
| 
      
 22 
     | 
    
         
            +
              opts.banner = <<BANNER
         
     | 
| 
      
 23 
     | 
    
         
            +
            JS Commander: Remote JavaScript Console
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            Usage: #{File.basename($0)} [options]
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            Options are:
         
     | 
| 
      
 28 
     | 
    
         
            +
            BANNER
         
     | 
| 
      
 29 
     | 
    
         
            +
              opts.separator ""
         
     | 
| 
      
 30 
     | 
    
         
            +
              opts.on("-p", "--port=PORT", Integer,
         
     | 
| 
      
 31 
     | 
    
         
            +
                      "Start proxy server on the specified port.",
         
     | 
| 
      
 32 
     | 
    
         
            +
                      "Default: 9000") { |OPTIONS[:port]| }
         
     | 
| 
      
 33 
     | 
    
         
            +
              opts.on("-h", "--help",
         
     | 
| 
      
 34 
     | 
    
         
            +
                      "Show this help message.") { puts opts; exit }
         
     | 
| 
      
 35 
     | 
    
         
            +
              opts.parse!(ARGV)
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              if MANDATORY_OPTIONS && MANDATORY_OPTIONS.find { |option| OPTIONS[option.to_sym].nil? }
         
     | 
| 
      
 38 
     | 
    
         
            +
                puts opts; exit
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
            # do stuff
         
     | 
| 
      
 43 
     | 
    
         
            +
            server = JSCommander::Broker.new(:Port => OPTIONS[:port], :AccessLog => [], :ProxyVia => nil)
         
     | 
| 
      
 44 
     | 
    
         
            +
            server.start
         
     | 
    
        data/lib/jscmd.rb
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            Dir[File.join(File.dirname(__FILE__), 'jscmd/**/*.rb')].sort.each { |lib| require lib }
         
     | 
    
        data/lib/jscmd/agent.js
    ADDED
    
    | 
         @@ -0,0 +1,253 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ({
         
     | 
| 
      
 2 
     | 
    
         
            +
                createXHR: function() {
         
     | 
| 
      
 3 
     | 
    
         
            +
                    if (window.ActiveXObject) {
         
     | 
| 
      
 4 
     | 
    
         
            +
                        try {
         
     | 
| 
      
 5 
     | 
    
         
            +
                            return new ActiveXObject("Msxml2.XMLHTTP");
         
     | 
| 
      
 6 
     | 
    
         
            +
                        } catch (e) {
         
     | 
| 
      
 7 
     | 
    
         
            +
                            try {
         
     | 
| 
      
 8 
     | 
    
         
            +
                                return new ActiveXObject("Microsoft.XMLHTTP");
         
     | 
| 
      
 9 
     | 
    
         
            +
                            } catch (e2) {
         
     | 
| 
      
 10 
     | 
    
         
            +
                                return null;
         
     | 
| 
      
 11 
     | 
    
         
            +
                            }
         
     | 
| 
      
 12 
     | 
    
         
            +
                        }
         
     | 
| 
      
 13 
     | 
    
         
            +
                    } else if (window.XMLHttpRequest) {
         
     | 
| 
      
 14 
     | 
    
         
            +
                        return new XMLHttpRequest();
         
     | 
| 
      
 15 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 16 
     | 
    
         
            +
                        return null;
         
     | 
| 
      
 17 
     | 
    
         
            +
                    }
         
     | 
| 
      
 18 
     | 
    
         
            +
                },
         
     | 
| 
      
 19 
     | 
    
         
            +
                    
         
     | 
| 
      
 20 
     | 
    
         
            +
                queue: [],
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                evaluate: function(script, recordValue) {
         
     | 
| 
      
 23 
     | 
    
         
            +
                    function dir(o) {
         
     | 
| 
      
 24 
     | 
    
         
            +
                        var list = [];
         
     | 
| 
      
 25 
     | 
    
         
            +
                        var maxNameLen = 0;
         
     | 
| 
      
 26 
     | 
    
         
            +
                        var valueLenLimit = 200;
         
     | 
| 
      
 27 
     | 
    
         
            +
                        for (name in o) {
         
     | 
| 
      
 28 
     | 
    
         
            +
                            var value = null;
         
     | 
| 
      
 29 
     | 
    
         
            +
                            try {
         
     | 
| 
      
 30 
     | 
    
         
            +
                                value = "" + (o[name] != null ? o[name] : null);
         
     | 
| 
      
 31 
     | 
    
         
            +
                            } catch (e) {
         
     | 
| 
      
 32 
     | 
    
         
            +
                                value = "[Error: " + e + "]";
         
     | 
| 
      
 33 
     | 
    
         
            +
                                // value = "[Error]";
         
     | 
| 
      
 34 
     | 
    
         
            +
                            }
         
     | 
| 
      
 35 
     | 
    
         
            +
                            value = value.replace(/\\/g, "\\\\");
         
     | 
| 
      
 36 
     | 
    
         
            +
                            value = value.replace(/\r/g, "");
         
     | 
| 
      
 37 
     | 
    
         
            +
                            value = value.replace(/\n/g, "\\n");
         
     | 
| 
      
 38 
     | 
    
         
            +
                            if (value.length > valueLenLimit) value = value.substring(0, valueLenLimit) + "...";
         
     | 
| 
      
 39 
     | 
    
         
            +
                            list.push([name, value]);
         
     | 
| 
      
 40 
     | 
    
         
            +
                            if (name.length > maxNameLen) maxNameLen = name.length;
         
     | 
| 
      
 41 
     | 
    
         
            +
                        }
         
     | 
| 
      
 42 
     | 
    
         
            +
                        for (var i = 0; i < list.length; i++) {
         
     | 
| 
      
 43 
     | 
    
         
            +
                            var name = list[i][0], value = list[i][1];
         
     | 
| 
      
 44 
     | 
    
         
            +
                            list[i] = name + (new Array(maxNameLen + 3 - name.length).join(" ")) + value;
         
     | 
| 
      
 45 
     | 
    
         
            +
                        }
         
     | 
| 
      
 46 
     | 
    
         
            +
                        return list.sort().join("\n");
         
     | 
| 
      
 47 
     | 
    
         
            +
                    }
         
     | 
| 
      
 48 
     | 
    
         
            +
                    var $_ = this.lastValue;
         
     | 
| 
      
 49 
     | 
    
         
            +
                    var value = eval(script);
         
     | 
| 
      
 50 
     | 
    
         
            +
                    if (recordValue) {
         
     | 
| 
      
 51 
     | 
    
         
            +
                        this.lastValue = value;
         
     | 
| 
      
 52 
     | 
    
         
            +
                    }
         
     | 
| 
      
 53 
     | 
    
         
            +
                    return value;
         
     | 
| 
      
 54 
     | 
    
         
            +
                },
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                poll: function() {
         
     | 
| 
      
 57 
     | 
    
         
            +
                    var content = this.queue.length > 0 ? this.queue.shift() : "";
         
     | 
| 
      
 58 
     | 
    
         
            +
                    var xhr = this.createXHR();
         
     | 
| 
      
 59 
     | 
    
         
            +
                    xhr.open("POST", "/_remote_js_proxy/poll", true);
         
     | 
| 
      
 60 
     | 
    
         
            +
                    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
         
     | 
| 
      
 61 
     | 
    
         
            +
                    var self = this;
         
     | 
| 
      
 62 
     | 
    
         
            +
                    xhr.onreadystatechange = function() {
         
     | 
| 
      
 63 
     | 
    
         
            +
                        if (xhr.readyState == 4) {
         
     | 
| 
      
 64 
     | 
    
         
            +
                            delete self.currentXHR;
         
     | 
| 
      
 65 
     | 
    
         
            +
                            try {
         
     | 
| 
      
 66 
     | 
    
         
            +
                                if (xhr.status == 200) {
         
     | 
| 
      
 67 
     | 
    
         
            +
                                    var text = xhr.responseText;
         
     | 
| 
      
 68 
     | 
    
         
            +
                                    if (text) {
         
     | 
| 
      
 69 
     | 
    
         
            +
                                        var value = null;
         
     | 
| 
      
 70 
     | 
    
         
            +
                                        try {
         
     | 
| 
      
 71 
     | 
    
         
            +
                                            var option = text.substring(0, 1);
         
     | 
| 
      
 72 
     | 
    
         
            +
                                            var script = text.substring(1, text.length);
         
     | 
| 
      
 73 
     | 
    
         
            +
                                            if (option == 'P') {
         
     | 
| 
      
 74 
     | 
    
         
            +
                                                // get properties for code completion
         
     | 
| 
      
 75 
     | 
    
         
            +
                                                var obj = self.evaluate.apply(window, [script, false]);
         
     | 
| 
      
 76 
     | 
    
         
            +
                                                value = "V" + self.getAllProperties(obj).join(",");
         
     | 
| 
      
 77 
     | 
    
         
            +
                                            } else if (option == 'E') {
         
     | 
| 
      
 78 
     | 
    
         
            +
                                                // just evaluate
         
     | 
| 
      
 79 
     | 
    
         
            +
                                                value = "V" + self.evaluate.apply(window, [script, true]);
         
     | 
| 
      
 80 
     | 
    
         
            +
                                            } else {
         
     | 
| 
      
 81 
     | 
    
         
            +
                                                value = "Ebad request: " + text;
         
     | 
| 
      
 82 
     | 
    
         
            +
                                            }
         
     | 
| 
      
 83 
     | 
    
         
            +
                                        } catch (e) {
         
     | 
| 
      
 84 
     | 
    
         
            +
                                            value = "E" + e.toString();
         
     | 
| 
      
 85 
     | 
    
         
            +
                                        }
         
     | 
| 
      
 86 
     | 
    
         
            +
                                        self.queue.push(value);
         
     | 
| 
      
 87 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 88 
     | 
    
         
            +
                                }
         
     | 
| 
      
 89 
     | 
    
         
            +
                            } catch (e) {
         
     | 
| 
      
 90 
     | 
    
         
            +
                                // failed to poll; ignore
         
     | 
| 
      
 91 
     | 
    
         
            +
                            }
         
     | 
| 
      
 92 
     | 
    
         
            +
                            if (!self.aborted) {
         
     | 
| 
      
 93 
     | 
    
         
            +
                                if (self.queue.length > 0) {
         
     | 
| 
      
 94 
     | 
    
         
            +
                                    self.poll();
         
     | 
| 
      
 95 
     | 
    
         
            +
                                } else {
         
     | 
| 
      
 96 
     | 
    
         
            +
                                    // if polling failed, try again later
         
     | 
| 
      
 97 
     | 
    
         
            +
                                    setTimeout(function() { self.poll() }, 5000);
         
     | 
| 
      
 98 
     | 
    
         
            +
                                }
         
     | 
| 
      
 99 
     | 
    
         
            +
                            }
         
     | 
| 
      
 100 
     | 
    
         
            +
                        }
         
     | 
| 
      
 101 
     | 
    
         
            +
                    }
         
     | 
| 
      
 102 
     | 
    
         
            +
                    this.currentXHR = xhr;
         
     | 
| 
      
 103 
     | 
    
         
            +
                    if (this.queue.length > 0) {
         
     | 
| 
      
 104 
     | 
    
         
            +
                        // mark that there are more messages pending
         
     | 
| 
      
 105 
     | 
    
         
            +
                        content = "+" + content;
         
     | 
| 
      
 106 
     | 
    
         
            +
                    }
         
     | 
| 
      
 107 
     | 
    
         
            +
                    xhr.send(encodeURI(content));
         
     | 
| 
      
 108 
     | 
    
         
            +
                },
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                startPoll: function() {
         
     | 
| 
      
 111 
     | 
    
         
            +
                    this.startPoll = function() {}
         
     | 
| 
      
 112 
     | 
    
         
            +
                    if (window.top.parent != window) return;
         
     | 
| 
      
 113 
     | 
    
         
            +
                    this.poll();
         
     | 
| 
      
 114 
     | 
    
         
            +
                },
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                abortPoll: function(retry) {
         
     | 
| 
      
 117 
     | 
    
         
            +
                    if (!retry) {
         
     | 
| 
      
 118 
     | 
    
         
            +
                        // don't retry any more
         
     | 
| 
      
 119 
     | 
    
         
            +
                        this.aborted = true;
         
     | 
| 
      
 120 
     | 
    
         
            +
                    }
         
     | 
| 
      
 121 
     | 
    
         
            +
                    if (this.currentXHR) {
         
     | 
| 
      
 122 
     | 
    
         
            +
                        this.currentXHR.abort();
         
     | 
| 
      
 123 
     | 
    
         
            +
                    }
         
     | 
| 
      
 124 
     | 
    
         
            +
                },
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                pushValue: function(value) {
         
     | 
| 
      
 127 
     | 
    
         
            +
                    this.queue.push(value);
         
     | 
| 
      
 128 
     | 
    
         
            +
                    this.abortPoll(true);
         
     | 
| 
      
 129 
     | 
    
         
            +
                    this.startPoll(); // in case startPoll has not been called yet
         
     | 
| 
      
 130 
     | 
    
         
            +
                },
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                attachEvent: function(event, handler) {
         
     | 
| 
      
 133 
     | 
    
         
            +
                    if (window.addEventListener) {
         
     | 
| 
      
 134 
     | 
    
         
            +
                        window.addEventListener(event, handler, false);
         
     | 
| 
      
 135 
     | 
    
         
            +
                    } else {
         
     | 
| 
      
 136 
     | 
    
         
            +
                        window.attachEvent("on" + event, handler);
         
     | 
| 
      
 137 
     | 
    
         
            +
                    }
         
     | 
| 
      
 138 
     | 
    
         
            +
                },
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                getAllProperties: function(obj) {
         
     | 
| 
      
 141 
     | 
    
         
            +
                    var result = [];
         
     | 
| 
      
 142 
     | 
    
         
            +
                    for (var i in obj) {
         
     | 
| 
      
 143 
     | 
    
         
            +
                        result.push(i);
         
     | 
| 
      
 144 
     | 
    
         
            +
                    }
         
     | 
| 
      
 145 
     | 
    
         
            +
                    for (var i = 0; i < this.dontEnums.length; i++) {
         
     | 
| 
      
 146 
     | 
    
         
            +
                        var e = this.dontEnums[i];
         
     | 
| 
      
 147 
     | 
    
         
            +
                        if (Object.prototype.toString.apply(obj).match(/object (\w+)/)) {
         
     | 
| 
      
 148 
     | 
    
         
            +
                            if (e.check(obj, RegExp.$1)) {
         
     | 
| 
      
 149 
     | 
    
         
            +
                                for (var k in e.properties) {
         
     | 
| 
      
 150 
     | 
    
         
            +
                                    var names = e.properties[k].split(/\s+/);
         
     | 
| 
      
 151 
     | 
    
         
            +
                                    for (var j = 0; j < names.length; j++) {
         
     | 
| 
      
 152 
     | 
    
         
            +
                                        if (obj[names[j]]) {
         
     | 
| 
      
 153 
     | 
    
         
            +
                                            result.push(names[j]);
         
     | 
| 
      
 154 
     | 
    
         
            +
                                        }
         
     | 
| 
      
 155 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 156 
     | 
    
         
            +
                                }
         
     | 
| 
      
 157 
     | 
    
         
            +
                            }
         
     | 
| 
      
 158 
     | 
    
         
            +
                        }
         
     | 
| 
      
 159 
     | 
    
         
            +
                    }
         
     | 
| 
      
 160 
     | 
    
         
            +
                    return result;
         
     | 
| 
      
 161 
     | 
    
         
            +
                },
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                // dontEnums is copied from jsh. thanks!
         
     | 
| 
      
 164 
     | 
    
         
            +
                // http://d.hatena.ne.jp/brazil/20061022
         
     | 
| 
      
 165 
     | 
    
         
            +
                dontEnums: [
         
     | 
| 
      
 166 
     | 
    
         
            +
            		{check: function(obj, objType){return objType=='String'}, properties: {
         
     | 
| 
      
 167 
     | 
    
         
            +
            			F:'charAt charCodeAt concat indexOf lastIndexOf match replace search slice split substr substring toLowerCase toUpperCase valueOf '+ 
         
     | 
| 
      
 168 
     | 
    
         
            +
            			  'anchor big blink bold fixed fontcolor fontsize italics link small strike sub sup',
         
     | 
| 
      
 169 
     | 
    
         
            +
            			N:'length'
         
     | 
| 
      
 170 
     | 
    
         
            +
            		}},
         
     | 
| 
      
 171 
     | 
    
         
            +
            		{check: function(obj, objType){return objType=='Array'}, properties: {
         
     | 
| 
      
 172 
     | 
    
         
            +
            			F:'concat join pop push unshift shift sort reverse slice splice toString valueOf '+
         
     | 
| 
      
 173 
     | 
    
         
            +
            				'every filter forEach map some',
         
     | 
| 
      
 174 
     | 
    
         
            +
            			N:'length'
         
     | 
| 
      
 175 
     | 
    
         
            +
            		}},
         
     | 
| 
      
 176 
     | 
    
         
            +
            		{check: function(obj, objType){return objType=='Boolean'}, properties: {
         
     | 
| 
      
 177 
     | 
    
         
            +
            			F:'toString valueOf'
         
     | 
| 
      
 178 
     | 
    
         
            +
            		}},
         
     | 
| 
      
 179 
     | 
    
         
            +
            		{check: function(obj, objType){return objType=='Date'}, properties: {
         
     | 
| 
      
 180 
     | 
    
         
            +
            			F:'getDate getYear getFullYear getHours getMilliseconds getMinutes getMonth getSeconds getTime getDay '+
         
     | 
| 
      
 181 
     | 
    
         
            +
            				'setDate setYear setFullYear setHours setMilliseconds setMinutes setMonth setSeconds setTime '+
         
     | 
| 
      
 182 
     | 
    
         
            +
            				'getUTCDate getUTCFullYear getUTCHours getUTCMilliseconds getUTCMinutes getUTCMonth getUTCSeconds getUTCDay '+
         
     | 
| 
      
 183 
     | 
    
         
            +
            				'setUTCDate setUTCFullYear setUTCHours setUTCMilliseconds setUTCMinutes setUTCMonth setUTCSeconds '+
         
     | 
| 
      
 184 
     | 
    
         
            +
            				'toGMTString toLocaleString toUTCString UTC getTimezoneOffset parse toString valueOf toSource'
         
     | 
| 
      
 185 
     | 
    
         
            +
            		}},
         
     | 
| 
      
 186 
     | 
    
         
            +
            		{check: function(obj, objType){return objType=='Number'}, properties: {
         
     | 
| 
      
 187 
     | 
    
         
            +
            			F:'toExponential toFixed toPrecision toSource toString valueOf'
         
     | 
| 
      
 188 
     | 
    
         
            +
            		}},
         
     | 
| 
      
 189 
     | 
    
         
            +
            		{check: function(obj, objType){return objType=='RegExp'}, properties: {
         
     | 
| 
      
 190 
     | 
    
         
            +
            			F:'exec test toSource toString',
         
     | 
| 
      
 191 
     | 
    
         
            +
            			B:'global ignoreCase multiline',
         
     | 
| 
      
 192 
     | 
    
         
            +
            			N:'lastIndex',
         
     | 
| 
      
 193 
     | 
    
         
            +
            			S:'source'
         
     | 
| 
      
 194 
     | 
    
         
            +
            		}},
         
     | 
| 
      
 195 
     | 
    
         
            +
            		{check: function(obj, objType){return obj.navigator}, properties: {
         
     | 
| 
      
 196 
     | 
    
         
            +
            			F:'Array String Number Date RegExp Boolean '+ 
         
     | 
| 
      
 197 
     | 
    
         
            +
            				'escape unescape decodeURI decodeURIComponent encodeURI encodeURIComponent '+
         
     | 
| 
      
 198 
     | 
    
         
            +
            				'eval isFinite isNaN parseFloat parseInt',
         
     | 
| 
      
 199 
     | 
    
         
            +
            			O:'Math undefined',
         
     | 
| 
      
 200 
     | 
    
         
            +
            			N:'Infinity NaN'
         
     | 
| 
      
 201 
     | 
    
         
            +
            		}},
         
     | 
| 
      
 202 
     | 
    
         
            +
            		{check: function(obj, objType){return objType=='Math'}, properties: {
         
     | 
| 
      
 203 
     | 
    
         
            +
            			F:'abs acos asin atan atan2 ceil cos exp floor log max min pow random round sin sqrt tan',
         
     | 
| 
      
 204 
     | 
    
         
            +
            			N:'E LN2 LN10 LOG2E LOG10E PI SQRT1_2 SQRT2'
         
     | 
| 
      
 205 
     | 
    
         
            +
            		}},
         
     | 
| 
      
 206 
     | 
    
         
            +
            		{check: function(obj, objType){return obj.MAX_VALUE}, properties: {
         
     | 
| 
      
 207 
     | 
    
         
            +
            			N:'MAX_VALUE MIN_VALUE NaN NEGATIVE_INFINITY POSITIVE_INFINITY'
         
     | 
| 
      
 208 
     | 
    
         
            +
            		}},
         
     | 
| 
      
 209 
     | 
    
         
            +
            		{check: function(obj, objType){return obj.fromCharCode}, properties: {
         
     | 
| 
      
 210 
     | 
    
         
            +
            			F:'fromCharCode'
         
     | 
| 
      
 211 
     | 
    
         
            +
            		}},
         
     | 
| 
      
 212 
     | 
    
         
            +
            		{check: function(obj, objType){return objType=='Function'}, properties: {
         
     | 
| 
      
 213 
     | 
    
         
            +
            			F:'apply call toSource toString'
         
     | 
| 
      
 214 
     | 
    
         
            +
                        }}
         
     | 
| 
      
 215 
     | 
    
         
            +
                ],
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                init: function() {
         
     | 
| 
      
 218 
     | 
    
         
            +
                    var self = this;
         
     | 
| 
      
 219 
     | 
    
         
            +
                    
         
     | 
| 
      
 220 
     | 
    
         
            +
                    this.attachEvent("abort", function() { self.abortPoll() });
         
     | 
| 
      
 221 
     | 
    
         
            +
                    this.attachEvent("unload", function() { self.abortPoll() });
         
     | 
| 
      
 222 
     | 
    
         
            +
                    this.attachEvent("pagehide", function() { self.abortPoll() });
         
     | 
| 
      
 223 
     | 
    
         
            +
                    
         
     | 
| 
      
 224 
     | 
    
         
            +
                    this.attachEvent("load", function() { self.startPoll() });
         
     | 
| 
      
 225 
     | 
    
         
            +
                    this.attachEvent("pageshow", function() { self.startPoll() });
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
                    window.onerror = function(message, file, line) {
         
     | 
| 
      
 228 
     | 
    
         
            +
                        self.pushValue("E" + 
         
     | 
| 
      
 229 
     | 
    
         
            +
                                       "Message: " + message + "\n" +
         
     | 
| 
      
 230 
     | 
    
         
            +
                                       "File: " + file + "\n" +
         
     | 
| 
      
 231 
     | 
    
         
            +
                                       "Line: " + line + "\n");
         
     | 
| 
      
 232 
     | 
    
         
            +
                    }
         
     | 
| 
      
 233 
     | 
    
         
            +
                    setTimeout(function() { self.startPoll() }, 3000);
         
     | 
| 
      
 234 
     | 
    
         
            +
                    
         
     | 
| 
      
 235 
     | 
    
         
            +
                    if (!window.console) {
         
     | 
| 
      
 236 
     | 
    
         
            +
                        window.console = {};
         
     | 
| 
      
 237 
     | 
    
         
            +
                        var levels = ["debug", "info", "warn", "error"];
         
     | 
| 
      
 238 
     | 
    
         
            +
                        for (var i = 0; i < levels.length; i++) {
         
     | 
| 
      
 239 
     | 
    
         
            +
                            (function() {
         
     | 
| 
      
 240 
     | 
    
         
            +
                                var level = levels[i];
         
     | 
| 
      
 241 
     | 
    
         
            +
                                window.console[level] = function() {
         
     | 
| 
      
 242 
     | 
    
         
            +
                                    var message = [];
         
     | 
| 
      
 243 
     | 
    
         
            +
                                    for (var i = 0; i < arguments.length; i++) {
         
     | 
| 
      
 244 
     | 
    
         
            +
                                        message.push(arguments[i]);
         
     | 
| 
      
 245 
     | 
    
         
            +
                                    }
         
     | 
| 
      
 246 
     | 
    
         
            +
                                    self.pushValue("V[" + level + "] " + message.join(", "));
         
     | 
| 
      
 247 
     | 
    
         
            +
                                }
         
     | 
| 
      
 248 
     | 
    
         
            +
                            })();
         
     | 
| 
      
 249 
     | 
    
         
            +
                        }
         
     | 
| 
      
 250 
     | 
    
         
            +
                        window.console.log = window.console.info;
         
     | 
| 
      
 251 
     | 
    
         
            +
                    }
         
     | 
| 
      
 252 
     | 
    
         
            +
                }
         
     | 
| 
      
 253 
     | 
    
         
            +
            }).init();
         
     | 
| 
         @@ -0,0 +1,140 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # asynchttpproxy.rb: Asynchronous HTTP Proxy Server
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright 2007 Shinya Kasatani
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
            # The original WEBrick::HTTPProxyServer sends response to the client
         
     | 
| 
      
 7 
     | 
    
         
            +
            # after the whole content has been downloaded to the proxy, 
         
     | 
| 
      
 8 
     | 
    
         
            +
            # while this AsyncHTTPProxyServer sends the response concurrently while
         
     | 
| 
      
 9 
     | 
    
         
            +
            # downloading the content.
         
     | 
| 
      
 10 
     | 
    
         
            +
            # 
         
     | 
| 
      
 11 
     | 
    
         
            +
            # Based on webrick/httpproxy.rb. The original copyright notice follows:
         
     | 
| 
      
 12 
     | 
    
         
            +
            #
         
     | 
| 
      
 13 
     | 
    
         
            +
            # httpproxy.rb -- HTTPProxy Class
         
     | 
| 
      
 14 
     | 
    
         
            +
            #
         
     | 
| 
      
 15 
     | 
    
         
            +
            # Author: IPR -- Internet Programming with Ruby -- writers
         
     | 
| 
      
 16 
     | 
    
         
            +
            # Copyright (c) 2002 GOTO Kentaro
         
     | 
| 
      
 17 
     | 
    
         
            +
            # Copyright (c) 2002 Internet Programming with Ruby writers. All rights
         
     | 
| 
      
 18 
     | 
    
         
            +
            # reserved.
         
     | 
| 
      
 19 
     | 
    
         
            +
            #
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            require 'stringio'
         
     | 
| 
      
 22 
     | 
    
         
            +
            require 'webrick/httpproxy'
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            module WEBrick
         
     | 
| 
      
 25 
     | 
    
         
            +
              class AsyncHTTPProxyServer < HTTPProxyServer
         
     | 
| 
      
 26 
     | 
    
         
            +
                def proxy_service(req, res)
         
     | 
| 
      
 27 
     | 
    
         
            +
                  # Proxy Authentication
         
     | 
| 
      
 28 
     | 
    
         
            +
                  proxy_auth(req, res)      
         
     | 
| 
      
 29 
     | 
    
         
            +
                  
         
     | 
| 
      
 30 
     | 
    
         
            +
                  # Create Request-URI to send to the origin server
         
     | 
| 
      
 31 
     | 
    
         
            +
                  uri  = req.request_uri
         
     | 
| 
      
 32 
     | 
    
         
            +
                  path = uri.path.dup
         
     | 
| 
      
 33 
     | 
    
         
            +
                  path << "?" << uri.query if uri.query
         
     | 
| 
      
 34 
     | 
    
         
            +
                  
         
     | 
| 
      
 35 
     | 
    
         
            +
                  # Choose header fields to transfer
         
     | 
| 
      
 36 
     | 
    
         
            +
                  header = Hash.new
         
     | 
| 
      
 37 
     | 
    
         
            +
                  choose_header(req, header)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  set_via(header)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  
         
     | 
| 
      
 40 
     | 
    
         
            +
                  # select upstream proxy server
         
     | 
| 
      
 41 
     | 
    
         
            +
                  if proxy = proxy_uri(req, res)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    proxy_host = proxy.host
         
     | 
| 
      
 43 
     | 
    
         
            +
                    proxy_port = proxy.port
         
     | 
| 
      
 44 
     | 
    
         
            +
                    if proxy.userinfo
         
     | 
| 
      
 45 
     | 
    
         
            +
                      credentials = "Basic " + [proxy.userinfo].pack("m*")
         
     | 
| 
      
 46 
     | 
    
         
            +
                      credentials.chomp!
         
     | 
| 
      
 47 
     | 
    
         
            +
                      header['proxy-authorization'] = credentials
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
                  end
         
     | 
| 
      
 50 
     | 
    
         
            +
                  
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  response = nil
         
     | 
| 
      
 53 
     | 
    
         
            +
                  q = Queue.new
         
     | 
| 
      
 54 
     | 
    
         
            +
                  p_reader, p_writer = IO.pipe
         
     | 
| 
      
 55 
     | 
    
         
            +
                  thread = Thread.start do
         
     | 
| 
      
 56 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 57 
     | 
    
         
            +
                      @logger.debug "downloading #{uri}"
         
     | 
| 
      
 58 
     | 
    
         
            +
                      http = Net::HTTP.new(uri.host, uri.port, proxy_host, proxy_port)
         
     | 
| 
      
 59 
     | 
    
         
            +
                      http.start{
         
     | 
| 
      
 60 
     | 
    
         
            +
                        if @config[:ProxyTimeout]
         
     | 
| 
      
 61 
     | 
    
         
            +
                          ##################################   these issues are 
         
     | 
| 
      
 62 
     | 
    
         
            +
                          http.open_timeout = 30   # secs  #   necessary (maybe bacause
         
     | 
| 
      
 63 
     | 
    
         
            +
                          http.read_timeout = 60   # secs  #   Ruby's bug, but why?)
         
     | 
| 
      
 64 
     | 
    
         
            +
                          ##################################
         
     | 
| 
      
 65 
     | 
    
         
            +
                        end
         
     | 
| 
      
 66 
     | 
    
         
            +
                        http_req = nil
         
     | 
| 
      
 67 
     | 
    
         
            +
                        http_req_body = nil
         
     | 
| 
      
 68 
     | 
    
         
            +
                        case req.request_method
         
     | 
| 
      
 69 
     | 
    
         
            +
                        when "GET"
         
     | 
| 
      
 70 
     | 
    
         
            +
                          http_req = Net::HTTP::Get.new(path, header)
         
     | 
| 
      
 71 
     | 
    
         
            +
                        when "POST"
         
     | 
| 
      
 72 
     | 
    
         
            +
                          http_req = Net::HTTP::Post.new(path, header)
         
     | 
| 
      
 73 
     | 
    
         
            +
                          http_req_body = req.body || ""
         
     | 
| 
      
 74 
     | 
    
         
            +
                        when "HEAD"
         
     | 
| 
      
 75 
     | 
    
         
            +
                          http_req = Net::HTTP::Head.new(path, header)
         
     | 
| 
      
 76 
     | 
    
         
            +
                        else
         
     | 
| 
      
 77 
     | 
    
         
            +
                          raise HTTPStatus::MethodNotAllowed,
         
     | 
| 
      
 78 
     | 
    
         
            +
                          "unsupported method `#{req.request_method}'."
         
     | 
| 
      
 79 
     | 
    
         
            +
                        end
         
     | 
| 
      
 80 
     | 
    
         
            +
                        http.request(http_req, http_req_body) do |response|
         
     | 
| 
      
 81 
     | 
    
         
            +
                          q.push response
         
     | 
| 
      
 82 
     | 
    
         
            +
                          size = 0
         
     | 
| 
      
 83 
     | 
    
         
            +
                          last_size = 0
         
     | 
| 
      
 84 
     | 
    
         
            +
                          response.read_body do |str|
         
     | 
| 
      
 85 
     | 
    
         
            +
                            last_size = size
         
     | 
| 
      
 86 
     | 
    
         
            +
                            size += str.size
         
     | 
| 
      
 87 
     | 
    
         
            +
                            if last_size / 500000 != size / 500000
         
     | 
| 
      
 88 
     | 
    
         
            +
                              @logger.debug "downloading #{uri}: size=#{size}"
         
     | 
| 
      
 89 
     | 
    
         
            +
                            end
         
     | 
| 
      
 90 
     | 
    
         
            +
                            p_writer.write str
         
     | 
| 
      
 91 
     | 
    
         
            +
                          end
         
     | 
| 
      
 92 
     | 
    
         
            +
                          @logger.debug "finished downloading #{uri}: size=#{size}"
         
     | 
| 
      
 93 
     | 
    
         
            +
                          p_writer.close
         
     | 
| 
      
 94 
     | 
    
         
            +
                        end
         
     | 
| 
      
 95 
     | 
    
         
            +
                      }
         
     | 
| 
      
 96 
     | 
    
         
            +
                    rescue Exception => err
         
     | 
| 
      
 97 
     | 
    
         
            +
                      logger.debug("#{err.class}: #{err.message}")
         
     | 
| 
      
 98 
     | 
    
         
            +
                      q.push err
         
     | 
| 
      
 99 
     | 
    
         
            +
                      # raise HTTPStatus::ServiceUnavailable, err.message
         
     | 
| 
      
 100 
     | 
    
         
            +
                    end
         
     | 
| 
      
 101 
     | 
    
         
            +
                  end
         
     | 
| 
      
 102 
     | 
    
         
            +
                  response = q.pop
         
     | 
| 
      
 103 
     | 
    
         
            +
                  if response.is_a?(Exception)
         
     | 
| 
      
 104 
     | 
    
         
            +
                    @logger.debug "failed to download #{uri}"
         
     | 
| 
      
 105 
     | 
    
         
            +
                    raise HTTPStatus::ServiceUnavailable, response.message
         
     | 
| 
      
 106 
     | 
    
         
            +
                  end
         
     | 
| 
      
 107 
     | 
    
         
            +
                  
         
     | 
| 
      
 108 
     | 
    
         
            +
                  # Persistent connction requirements are mysterious for me.
         
     | 
| 
      
 109 
     | 
    
         
            +
                  # So I will close the connection in every response.
         
     | 
| 
      
 110 
     | 
    
         
            +
                  res['proxy-connection'] = "close"
         
     | 
| 
      
 111 
     | 
    
         
            +
                  res['connection'] = "close"
         
     | 
| 
      
 112 
     | 
    
         
            +
                  
         
     | 
| 
      
 113 
     | 
    
         
            +
                  # Convert Net::HTTP::HTTPResponse to WEBrick::HTTPProxy
         
     | 
| 
      
 114 
     | 
    
         
            +
                  res.status = response.code.to_i
         
     | 
| 
      
 115 
     | 
    
         
            +
                  choose_header(response, res)
         
     | 
| 
      
 116 
     | 
    
         
            +
                  set_cookie(response, res)
         
     | 
| 
      
 117 
     | 
    
         
            +
                  set_via(res)
         
     | 
| 
      
 118 
     | 
    
         
            +
                  res.body = p_reader
         
     | 
| 
      
 119 
     | 
    
         
            +
                  def res.flush_body
         
     | 
| 
      
 120 
     | 
    
         
            +
                    if @body.is_a?(IO)
         
     | 
| 
      
 121 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 122 
     | 
    
         
            +
                        str_body = @body.read
         
     | 
| 
      
 123 
     | 
    
         
            +
                      ensure
         
     | 
| 
      
 124 
     | 
    
         
            +
                        @body.close
         
     | 
| 
      
 125 
     | 
    
         
            +
                      end
         
     | 
| 
      
 126 
     | 
    
         
            +
                      @body = str_body
         
     | 
| 
      
 127 
     | 
    
         
            +
                    end
         
     | 
| 
      
 128 
     | 
    
         
            +
                    @body
         
     | 
| 
      
 129 
     | 
    
         
            +
                  end
         
     | 
| 
      
 130 
     | 
    
         
            +
                  
         
     | 
| 
      
 131 
     | 
    
         
            +
                  @logger.debug "downloading #{uri}: content-length=#{res.header['content-length']}"
         
     | 
| 
      
 132 
     | 
    
         
            +
                  
         
     | 
| 
      
 133 
     | 
    
         
            +
                  # Process contents
         
     | 
| 
      
 134 
     | 
    
         
            +
                  if handler = @config[:ProxyContentHandler]
         
     | 
| 
      
 135 
     | 
    
         
            +
                    handler.call(req, res)
         
     | 
| 
      
 136 
     | 
    
         
            +
                  end
         
     | 
| 
      
 137 
     | 
    
         
            +
                end
         
     | 
| 
      
 138 
     | 
    
         
            +
              end
         
     | 
| 
      
 139 
     | 
    
         
            +
            end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
         @@ -0,0 +1,339 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #
         
     | 
| 
      
 2 
     | 
    
         
            +
            # jscommander.rb: Remote JavaScript Console
         
     | 
| 
      
 3 
     | 
    
         
            +
            #
         
     | 
| 
      
 4 
     | 
    
         
            +
            # Copyright 2007 Shinya Kasatani
         
     | 
| 
      
 5 
     | 
    
         
            +
            #
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            require 'uri'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'thread'
         
     | 
| 
      
 9 
     | 
    
         
            +
            require 'webrick'
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'zlib'
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            module JSCommander
         
     | 
| 
      
 13 
     | 
    
         
            +
              SCRIPT_DIR = "/_remote_js_proxy/"
         
     | 
| 
      
 14 
     | 
    
         
            +
              
         
     | 
| 
      
 15 
     | 
    
         
            +
              class PipeQueue
         
     | 
| 
      
 16 
     | 
    
         
            +
                attr_reader :reader, :writer
         
     | 
| 
      
 17 
     | 
    
         
            +
                
         
     | 
| 
      
 18 
     | 
    
         
            +
                def initialize
         
     | 
| 
      
 19 
     | 
    
         
            +
                  @reader, @writer = IO.pipe
         
     | 
| 
      
 20 
     | 
    
         
            +
                end
         
     | 
| 
      
 21 
     | 
    
         
            +
                
         
     | 
| 
      
 22 
     | 
    
         
            +
                def push(obj)
         
     | 
| 
      
 23 
     | 
    
         
            +
                  data = Marshal.dump(obj)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  @writer.write([data.size].pack("N") + data)
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def pop
         
     | 
| 
      
 28 
     | 
    
         
            +
                  size = @reader.read(4).unpack("N")[0]
         
     | 
| 
      
 29 
     | 
    
         
            +
                  Marshal.load(@reader.read(size))
         
     | 
| 
      
 30 
     | 
    
         
            +
                end
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
              # types are: V: value, E: error, A: active message from proxy
         
     | 
| 
      
 34 
     | 
    
         
            +
              Message = Struct.new(:value, :type, :clients)
         
     | 
| 
      
 35 
     | 
    
         
            +
              
         
     | 
| 
      
 36 
     | 
    
         
            +
              class Broker
         
     | 
| 
      
 37 
     | 
    
         
            +
                attr_reader :cmd_queue, :msg_queue
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                def initialize(opts = {})
         
     | 
| 
      
 40 
     | 
    
         
            +
                  @cmd_queue = PipeQueue.new
         
     | 
| 
      
 41 
     | 
    
         
            +
                  @msg_queue = PipeQueue.new
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @proxy = ProxyServer.new(self, opts)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  @shell = Shell.new(self)
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
                
         
     | 
| 
      
 46 
     | 
    
         
            +
                def start
         
     | 
| 
      
 47 
     | 
    
         
            +
                  @proxy_pid = fork do
         
     | 
| 
      
 48 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 49 
     | 
    
         
            +
                      Signal.trap('INT') {}
         
     | 
| 
      
 50 
     | 
    
         
            +
                      Signal.trap('TERM') { @proxy.shutdown }
         
     | 
| 
      
 51 
     | 
    
         
            +
                      IO.for_fd(0).close
         
     | 
| 
      
 52 
     | 
    
         
            +
                      @proxy.start
         
     | 
| 
      
 53 
     | 
    
         
            +
                    rescue Exception => e
         
     | 
| 
      
 54 
     | 
    
         
            +
                      p e
         
     | 
| 
      
 55 
     | 
    
         
            +
                    end
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
                  Signal.trap("TERM") { shutdown }
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @shell.run # @shell.run should block
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                def shutdown
         
     | 
| 
      
 62 
     | 
    
         
            +
                  $stderr.puts "shutdown"
         
     | 
| 
      
 63 
     | 
    
         
            +
                  Process.kill "TERM", @proxy_pid
         
     | 
| 
      
 64 
     | 
    
         
            +
                  Process.waitall
         
     | 
| 
      
 65 
     | 
    
         
            +
                  exit(0)
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
              end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
              class Shell
         
     | 
| 
      
 70 
     | 
    
         
            +
                class SimpleConsole
         
     | 
| 
      
 71 
     | 
    
         
            +
                  def show_banner
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                  def readline
         
     | 
| 
      
 75 
     | 
    
         
            +
                    line = $stdin.readline
         
     | 
| 
      
 76 
     | 
    
         
            +
                    line.chomp! if line
         
     | 
| 
      
 77 
     | 
    
         
            +
                    line
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
                  
         
     | 
| 
      
 80 
     | 
    
         
            +
                  def close
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
                
         
     | 
| 
      
 84 
     | 
    
         
            +
                class ReadlineConsole
         
     | 
| 
      
 85 
     | 
    
         
            +
                  HISTORY_PATH = "~/.jscmd_history"
         
     | 
| 
      
 86 
     | 
    
         
            +
                  
         
     | 
| 
      
 87 
     | 
    
         
            +
                  def history_path
         
     | 
| 
      
 88 
     | 
    
         
            +
                    File.expand_path(HISTORY_PATH)
         
     | 
| 
      
 89 
     | 
    
         
            +
                  end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                  def initialize(shell)
         
     | 
| 
      
 92 
     | 
    
         
            +
                    @shell = shell
         
     | 
| 
      
 93 
     | 
    
         
            +
                    require 'readline'
         
     | 
| 
      
 94 
     | 
    
         
            +
                    if File.exist?(history_path)
         
     | 
| 
      
 95 
     | 
    
         
            +
                      hist = File.readlines(history_path).map{|line| line.chomp}
         
     | 
| 
      
 96 
     | 
    
         
            +
                      Readline::HISTORY.push(*hist)
         
     | 
| 
      
 97 
     | 
    
         
            +
                    end
         
     | 
| 
      
 98 
     | 
    
         
            +
                    Readline.basic_word_break_characters = " \t\n\\`@><=;|&{([+-*/%"
         
     | 
| 
      
 99 
     | 
    
         
            +
                    Readline.completion_append_character = nil
         
     | 
| 
      
 100 
     | 
    
         
            +
                    Readline.completion_proc = proc do |word|
         
     | 
| 
      
 101 
     | 
    
         
            +
                      if word =~ /\.$/
         
     | 
| 
      
 102 
     | 
    
         
            +
                        @shell.object_props($`).map{|name| word + name}
         
     | 
| 
      
 103 
     | 
    
         
            +
                      elsif word =~ /\.([^.]+)$/
         
     | 
| 
      
 104 
     | 
    
         
            +
                        prefix = $1
         
     | 
| 
      
 105 
     | 
    
         
            +
                        parent = $`
         
     | 
| 
      
 106 
     | 
    
         
            +
                        props = @shell.object_props(parent)
         
     | 
| 
      
 107 
     | 
    
         
            +
                        props.select{|name|name[0...(prefix.size)] == prefix}.map{|name| "#{parent}.#{name}"}
         
     | 
| 
      
 108 
     | 
    
         
            +
                      else
         
     | 
| 
      
 109 
     | 
    
         
            +
                        props = @shell.object_props("this")
         
     | 
| 
      
 110 
     | 
    
         
            +
                        prefix = word
         
     | 
| 
      
 111 
     | 
    
         
            +
                        props.select{|name|name[0...(prefix.size)] == prefix}
         
     | 
| 
      
 112 
     | 
    
         
            +
                      end
         
     | 
| 
      
 113 
     | 
    
         
            +
                    end
         
     | 
| 
      
 114 
     | 
    
         
            +
                  end
         
     | 
| 
      
 115 
     | 
    
         
            +
                  
         
     | 
| 
      
 116 
     | 
    
         
            +
                  def show_banner
         
     | 
| 
      
 117 
     | 
    
         
            +
                    puts "Press Ctrl+D to exit."
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
                  
         
     | 
| 
      
 120 
     | 
    
         
            +
                  def close
         
     | 
| 
      
 121 
     | 
    
         
            +
                    open(history_path, "ab") do |f|
         
     | 
| 
      
 122 
     | 
    
         
            +
                      Readline::HISTORY.each{|line| f.puts(line)}
         
     | 
| 
      
 123 
     | 
    
         
            +
                    end
         
     | 
| 
      
 124 
     | 
    
         
            +
                  end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                  def readline
         
     | 
| 
      
 127 
     | 
    
         
            +
                    line = Readline.readline("#{@shell.clients}> ", true)
         
     | 
| 
      
 128 
     | 
    
         
            +
                    Readline::HISTORY.pop if /^\s*$/ =~ line
         
     | 
| 
      
 129 
     | 
    
         
            +
                    line
         
     | 
| 
      
 130 
     | 
    
         
            +
                  end
         
     | 
| 
      
 131 
     | 
    
         
            +
                end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                def console
         
     | 
| 
      
 134 
     | 
    
         
            +
                  @console ||= $stdin.tty? ? ReadlineConsole.new(self) : SimpleConsole.new
         
     | 
| 
      
 135 
     | 
    
         
            +
                end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                attr_reader :clients
         
     | 
| 
      
 138 
     | 
    
         
            +
                
         
     | 
| 
      
 139 
     | 
    
         
            +
                def initialize(broker)
         
     | 
| 
      
 140 
     | 
    
         
            +
                  @broker = broker
         
     | 
| 
      
 141 
     | 
    
         
            +
                  @clients = nil
         
     | 
| 
      
 142 
     | 
    
         
            +
                  @msg_lock = Mutex.new
         
     | 
| 
      
 143 
     | 
    
         
            +
                end
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                def send_script(line, &handler)
         
     | 
| 
      
 146 
     | 
    
         
            +
                  @msg_lock.synchronize do
         
     | 
| 
      
 147 
     | 
    
         
            +
                    @broker.cmd_queue.push(line)
         
     | 
| 
      
 148 
     | 
    
         
            +
                    yield read_msg
         
     | 
| 
      
 149 
     | 
    
         
            +
                  end
         
     | 
| 
      
 150 
     | 
    
         
            +
                end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                def read_msg
         
     | 
| 
      
 153 
     | 
    
         
            +
                  msg = @broker.msg_queue.pop
         
     | 
| 
      
 154 
     | 
    
         
            +
                  # p msg
         
     | 
| 
      
 155 
     | 
    
         
            +
                  @clients = msg.clients
         
     | 
| 
      
 156 
     | 
    
         
            +
                  msg
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                def object_props(object)
         
     | 
| 
      
 160 
     | 
    
         
            +
                  send_script("P" + object) do |r|
         
     | 
| 
      
 161 
     | 
    
         
            +
                    if r.type == "V" && r.value
         
     | 
| 
      
 162 
     | 
    
         
            +
                      r.value.split(/,/)
         
     | 
| 
      
 163 
     | 
    
         
            +
                    else
         
     | 
| 
      
 164 
     | 
    
         
            +
                      []
         
     | 
| 
      
 165 
     | 
    
         
            +
                    end
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
      
 167 
     | 
    
         
            +
                end
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                def run
         
     | 
| 
      
 170 
     | 
    
         
            +
                  # read and print messages in background
         
     | 
| 
      
 171 
     | 
    
         
            +
                  Thread.start do
         
     | 
| 
      
 172 
     | 
    
         
            +
                    while IO.select([@broker.msg_queue.reader], nil, nil, nil)
         
     | 
| 
      
 173 
     | 
    
         
            +
                      @msg_lock.synchronize do
         
     | 
| 
      
 174 
     | 
    
         
            +
                        if IO.select([@broker.msg_queue.reader], nil, nil, 0)
         
     | 
| 
      
 175 
     | 
    
         
            +
                          msg = read_msg
         
     | 
| 
      
 176 
     | 
    
         
            +
                          puts msg.value || ""
         
     | 
| 
      
 177 
     | 
    
         
            +
                          Process.kill "INT", $$  # interrupt readline
         
     | 
| 
      
 178 
     | 
    
         
            +
                        end
         
     | 
| 
      
 179 
     | 
    
         
            +
                      end
         
     | 
| 
      
 180 
     | 
    
         
            +
                    end
         
     | 
| 
      
 181 
     | 
    
         
            +
                  end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                  console.show_banner
         
     | 
| 
      
 184 
     | 
    
         
            +
                  
         
     | 
| 
      
 185 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 186 
     | 
    
         
            +
                    loop do
         
     | 
| 
      
 187 
     | 
    
         
            +
                      break unless line = console.readline
         
     | 
| 
      
 188 
     | 
    
         
            +
                      send_script("E" + line) do |msg|
         
     | 
| 
      
 189 
     | 
    
         
            +
                        puts msg.value if msg.value
         
     | 
| 
      
 190 
     | 
    
         
            +
                      end
         
     | 
| 
      
 191 
     | 
    
         
            +
                    end
         
     | 
| 
      
 192 
     | 
    
         
            +
                  rescue Interrupt
         
     | 
| 
      
 193 
     | 
    
         
            +
                    retry
         
     | 
| 
      
 194 
     | 
    
         
            +
                  rescue SystemExit
         
     | 
| 
      
 195 
     | 
    
         
            +
                    return
         
     | 
| 
      
 196 
     | 
    
         
            +
                  rescue Exception => e
         
     | 
| 
      
 197 
     | 
    
         
            +
                    $stderr.puts "#{e.inspect} at:\n#{e.backtrace.join("\n")}"
         
     | 
| 
      
 198 
     | 
    
         
            +
                  ensure
         
     | 
| 
      
 199 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 200 
     | 
    
         
            +
                      console.close
         
     | 
| 
      
 201 
     | 
    
         
            +
                    rescue Exception => e
         
     | 
| 
      
 202 
     | 
    
         
            +
                      $stderr.puts "failed to close console: #{e.inspect}"
         
     | 
| 
      
 203 
     | 
    
         
            +
                    end
         
     | 
| 
      
 204 
     | 
    
         
            +
                  end
         
     | 
| 
      
 205 
     | 
    
         
            +
                  @broker.shutdown
         
     | 
| 
      
 206 
     | 
    
         
            +
                end
         
     | 
| 
      
 207 
     | 
    
         
            +
              end
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
              class ProxyServer < WEBrick::AsyncHTTPProxyServer
         
     | 
| 
      
 210 
     | 
    
         
            +
                def initialize(broker, args = {})
         
     | 
| 
      
 211 
     | 
    
         
            +
                  @broker = broker
         
     | 
| 
      
 212 
     | 
    
         
            +
                  @cmd_queue = PipeQueue.new
         
     | 
| 
      
 213 
     | 
    
         
            +
                  @clients = []
         
     | 
| 
      
 214 
     | 
    
         
            +
                  super({:ProxyContentHandler => method(:handle_content).to_proc}.merge(args))
         
     | 
| 
      
 215 
     | 
    
         
            +
                end
         
     | 
| 
      
 216 
     | 
    
         
            +
             
     | 
| 
      
 217 
     | 
    
         
            +
                def start
         
     | 
| 
      
 218 
     | 
    
         
            +
                  Thread.start do
         
     | 
| 
      
 219 
     | 
    
         
            +
                    sleep 1
         
     | 
| 
      
 220 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 221 
     | 
    
         
            +
                      poll_cmd_queue
         
     | 
| 
      
 222 
     | 
    
         
            +
                    rescue Exception => e
         
     | 
| 
      
 223 
     | 
    
         
            +
                      p e
         
     | 
| 
      
 224 
     | 
    
         
            +
                    end
         
     | 
| 
      
 225 
     | 
    
         
            +
                  end
         
     | 
| 
      
 226 
     | 
    
         
            +
                  super
         
     | 
| 
      
 227 
     | 
    
         
            +
                end
         
     | 
| 
      
 228 
     | 
    
         
            +
             
     | 
| 
      
 229 
     | 
    
         
            +
                def service(req, res)
         
     | 
| 
      
 230 
     | 
    
         
            +
                  if req.path == "#{SCRIPT_DIR}agent.js"
         
     | 
| 
      
 231 
     | 
    
         
            +
                    res.content_type = "application/x-javascript"
         
     | 
| 
      
 232 
     | 
    
         
            +
                    res.body = File.read(File.join(File.dirname(__FILE__), "agent.js"))
         
     | 
| 
      
 233 
     | 
    
         
            +
                  elsif req.path == "#{SCRIPT_DIR}poll"
         
     | 
| 
      
 234 
     | 
    
         
            +
                    serve_script(req, res)
         
     | 
| 
      
 235 
     | 
    
         
            +
                  else
         
     | 
| 
      
 236 
     | 
    
         
            +
                    if req.header["accept-encoding"] && !req.header["accept-encoding"].empty?
         
     | 
| 
      
 237 
     | 
    
         
            +
                      if req.header["accept-encoding"].first.split(/,/).include?("gzip")
         
     | 
| 
      
 238 
     | 
    
         
            +
                        req.header["accept-encoding"] = ["gzip"]
         
     | 
| 
      
 239 
     | 
    
         
            +
                      else
         
     | 
| 
      
 240 
     | 
    
         
            +
                        req.header.delete "accept-encoding"
         
     | 
| 
      
 241 
     | 
    
         
            +
                      end
         
     | 
| 
      
 242 
     | 
    
         
            +
                    end
         
     | 
| 
      
 243 
     | 
    
         
            +
                    super
         
     | 
| 
      
 244 
     | 
    
         
            +
                  end
         
     | 
| 
      
 245 
     | 
    
         
            +
                end
         
     | 
| 
      
 246 
     | 
    
         
            +
                
         
     | 
| 
      
 247 
     | 
    
         
            +
                def format_clients
         
     | 
| 
      
 248 
     | 
    
         
            +
                  @clients.map{|c|"[#{URI.parse(c.header["referer"].to_s).host}]"}.join(",")
         
     | 
| 
      
 249 
     | 
    
         
            +
                end
         
     | 
| 
      
 250 
     | 
    
         
            +
             
     | 
| 
      
 251 
     | 
    
         
            +
                def poll_cmd_queue
         
     | 
| 
      
 252 
     | 
    
         
            +
                  while @status == :Running
         
     | 
| 
      
 253 
     | 
    
         
            +
                    cmd = @broker.cmd_queue.pop
         
     | 
| 
      
 254 
     | 
    
         
            +
                    cmd_line = cmd[1...(cmd.size)]
         
     | 
| 
      
 255 
     | 
    
         
            +
                    if cmd_line.strip.empty?
         
     | 
| 
      
 256 
     | 
    
         
            +
                      @broker.msg_queue.push(Message.new(nil, "V", format_clients))
         
     | 
| 
      
 257 
     | 
    
         
            +
                    else
         
     | 
| 
      
 258 
     | 
    
         
            +
                      @cmd_queue.push(cmd)
         
     | 
| 
      
 259 
     | 
    
         
            +
                    end
         
     | 
| 
      
 260 
     | 
    
         
            +
                  end
         
     | 
| 
      
 261 
     | 
    
         
            +
                end
         
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
                def serve_script(req, res)
         
     | 
| 
      
 264 
     | 
    
         
            +
                  # puts "serve:#{req.body}"
         
     | 
| 
      
 265 
     | 
    
         
            +
                  @clients << req
         
     | 
| 
      
 266 
     | 
    
         
            +
                  if req.body && req.body =~ /^(\+?)([VE])/
         
     | 
| 
      
 267 
     | 
    
         
            +
                    more = $1 == '+'
         
     | 
| 
      
 268 
     | 
    
         
            +
                    type = $2
         
     | 
| 
      
 269 
     | 
    
         
            +
                    # V: value
         
     | 
| 
      
 270 
     | 
    
         
            +
                    # E: error
         
     | 
| 
      
 271 
     | 
    
         
            +
                    @broker.msg_queue.push Message.new(URI.decode($'), type, format_clients)
         
     | 
| 
      
 272 
     | 
    
         
            +
                    if more
         
     | 
| 
      
 273 
     | 
    
         
            +
                      res.content_type = "text/plain"
         
     | 
| 
      
 274 
     | 
    
         
            +
                      res.body = ''
         
     | 
| 
      
 275 
     | 
    
         
            +
                      return
         
     | 
| 
      
 276 
     | 
    
         
            +
                    end
         
     | 
| 
      
 277 
     | 
    
         
            +
                  else
         
     | 
| 
      
 278 
     | 
    
         
            +
                    # empty message - maybe a new client connected?
         
     | 
| 
      
 279 
     | 
    
         
            +
                    @broker.msg_queue.push Message.new(nil, "A", format_clients)
         
     | 
| 
      
 280 
     | 
    
         
            +
                  end
         
     | 
| 
      
 281 
     | 
    
         
            +
                  while @status == :Running
         
     | 
| 
      
 282 
     | 
    
         
            +
                    req_socket = req.instance_eval{@socket}
         
     | 
| 
      
 283 
     | 
    
         
            +
                    sockets = [req_socket, @cmd_queue.reader]
         
     | 
| 
      
 284 
     | 
    
         
            +
                    if @clients.first != req
         
     | 
| 
      
 285 
     | 
    
         
            +
                      # don't poll cmd_queue if this is request is not the first one
         
     | 
| 
      
 286 
     | 
    
         
            +
                      sockets.pop
         
     | 
| 
      
 287 
     | 
    
         
            +
                    end
         
     | 
| 
      
 288 
     | 
    
         
            +
                    r = IO.select(sockets, nil, nil, 1)
         
     | 
| 
      
 289 
     | 
    
         
            +
                    if r
         
     | 
| 
      
 290 
     | 
    
         
            +
                      if r[0].include?(@cmd_queue.reader)
         
     | 
| 
      
 291 
     | 
    
         
            +
                        line = @cmd_queue.pop
         
     | 
| 
      
 292 
     | 
    
         
            +
                        res.content_type = "text/plain"
         
     | 
| 
      
 293 
     | 
    
         
            +
                        res.body = line
         
     | 
| 
      
 294 
     | 
    
         
            +
                        return
         
     | 
| 
      
 295 
     | 
    
         
            +
                      elsif r[0].include?(req_socket)
         
     | 
| 
      
 296 
     | 
    
         
            +
                        @clients.delete(req); req = nil
         
     | 
| 
      
 297 
     | 
    
         
            +
                        @broker.msg_queue.push(Message.new("aborted", "A", format_clients))
         
     | 
| 
      
 298 
     | 
    
         
            +
                        raise WEBrick::HTTPStatus::EOFError
         
     | 
| 
      
 299 
     | 
    
         
            +
                      end
         
     | 
| 
      
 300 
     | 
    
         
            +
                    end
         
     | 
| 
      
 301 
     | 
    
         
            +
                  end
         
     | 
| 
      
 302 
     | 
    
         
            +
                  # server is shutting down
         
     | 
| 
      
 303 
     | 
    
         
            +
                  raise WEBrick::HTTPStatus::EOFError
         
     | 
| 
      
 304 
     | 
    
         
            +
                ensure
         
     | 
| 
      
 305 
     | 
    
         
            +
                  @clients.delete(req) if req
         
     | 
| 
      
 306 
     | 
    
         
            +
                end
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
      
 308 
     | 
    
         
            +
                def handle_content(req, res)
         
     | 
| 
      
 309 
     | 
    
         
            +
                  # $stderr.puts "handle_content:type=#{res.content_type}, status=#{res.status}, encoding=#{res.header["content-encoding"]}"
         
     | 
| 
      
 310 
     | 
    
         
            +
                  if res.content_type =~ %r{^text/html} && res.status == 200
         
     | 
| 
      
 311 
     | 
    
         
            +
                    res.flush_body
         
     | 
| 
      
 312 
     | 
    
         
            +
                    # we cannot always trust content_type, so check if the content looks like html
         
     | 
| 
      
 313 
     | 
    
         
            +
                    body = res.body
         
     | 
| 
      
 314 
     | 
    
         
            +
                    if res.header["content-encoding"] == "gzip"
         
     | 
| 
      
 315 
     | 
    
         
            +
                      body = Zlib::GzipReader.new(StringIO.new(body)).read
         
     | 
| 
      
 316 
     | 
    
         
            +
                    end
         
     | 
| 
      
 317 
     | 
    
         
            +
                    if body =~ /^\s*</
         
     | 
| 
      
 318 
     | 
    
         
            +
                      body = body.dup
         
     | 
| 
      
 319 
     | 
    
         
            +
                      # puts "injecting javascript"
         
     | 
| 
      
 320 
     | 
    
         
            +
                      script_tag = '<script type="text/javascript" src="/_remote_js_proxy/agent.js"></script>'
         
     | 
| 
      
 321 
     | 
    
         
            +
                      unless body.sub!(%r{<head( .*?)?>}i){|s|s+script_tag}
         
     | 
| 
      
 322 
     | 
    
         
            +
                        body = script_tag + body
         
     | 
| 
      
 323 
     | 
    
         
            +
                      end
         
     | 
| 
      
 324 
     | 
    
         
            +
                      if res.header["content-encoding"] == "gzip"
         
     | 
| 
      
 325 
     | 
    
         
            +
                        io = StringIO.new
         
     | 
| 
      
 326 
     | 
    
         
            +
                        writer = Zlib::GzipWriter.new(io)
         
     | 
| 
      
 327 
     | 
    
         
            +
                        writer.write(body)
         
     | 
| 
      
 328 
     | 
    
         
            +
                        writer.close
         
     | 
| 
      
 329 
     | 
    
         
            +
                        res.body = io.string
         
     | 
| 
      
 330 
     | 
    
         
            +
                      else
         
     | 
| 
      
 331 
     | 
    
         
            +
                        res.body = body
         
     | 
| 
      
 332 
     | 
    
         
            +
                      end
         
     | 
| 
      
 333 
     | 
    
         
            +
                      res.content_length = res.body.size if res.content_length
         
     | 
| 
      
 334 
     | 
    
         
            +
                    end
         
     | 
| 
      
 335 
     | 
    
         
            +
                  end
         
     | 
| 
      
 336 
     | 
    
         
            +
                end
         
     | 
| 
      
 337 
     | 
    
         
            +
              end
         
     | 
| 
      
 338 
     | 
    
         
            +
            end
         
     | 
| 
      
 339 
     | 
    
         
            +
             
     |