├── package.json ├── LICENSE ├── test ├── runner.js ├── test.js └── timeline.js ├── README.md ├── index.js ├── select-min.js └── select.js /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-select", 3 | "description": "Traverse and modify objects with JSONSelect selectors", 4 | "version": "0.6.0", 5 | "author": "Heather Arthur ", 6 | "repository": { 7 | "type": "git", 8 | "url": "http://github.com/harthur/js-select.git" 9 | }, 10 | "main": "./index", 11 | "dependencies": { 12 | "traverse": "0.4.x", 13 | "JSONSelect": "0.2.1" 14 | }, 15 | "devDependencies": { 16 | "nomnom": "0.6.x", 17 | "color": "0.3.x" 18 | }, 19 | "keywords": ["json"] 20 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Heather Arthur 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /test/runner.js: -------------------------------------------------------------------------------- 1 | /* node runner for the JSONSelect conformance tests 2 | https://github.com/lloyd/JSONSelectTests */ 3 | 4 | var assert = require("assert"), 5 | fs = require("fs"), 6 | path = require("path"), 7 | colors = require("colors"), 8 | traverse = require("traverse") 9 | select = require("../index"); 10 | 11 | var options = require("nomnom").opts({ 12 | directory: { 13 | abbr: 'd', 14 | help: 'directory of tests to run', 15 | metavar: 'PATH', 16 | default: __dirname + "/level_1" 17 | } 18 | }).parseArgs(); 19 | 20 | var directory = options.directory, 21 | files = fs.readdirSync(directory); 22 | 23 | var jsonFiles = files.filter(function(file) { 24 | return path.extname(file) == ".json"; 25 | }); 26 | 27 | jsonFiles.forEach(function(file) { 28 | var jsonName = file.replace(/\..*$/, ""), 29 | json = JSON.parse(fs.readFileSync(path.join(directory, file), "utf-8")); 30 | 31 | var selFiles = files.filter(function(file) { 32 | return file.indexOf(jsonName) == 0 && path.extname(file) == ".selector" 33 | }) 34 | 35 | selFiles.forEach(function(file) { 36 | var test = file.replace(/\..*$/, ""); 37 | var selector = fs.readFileSync(path.join(directory, file), "utf-8"); 38 | var output = fs.readFileSync(path.join(directory, test + ".output"), "utf-8"); 39 | 40 | var expected = JSON.parse(output).sort(sort); 41 | var got = select(json, selector).nodes().sort(sort); 42 | try { 43 | assert.deepEqual(got, expected); 44 | } 45 | catch(AssertionError) { 46 | console.log("\nfail".red + " " + test + "\ngot: ".blue + JSON.stringify(got) 47 | + "\n\expected: ".blue + JSON.stringify(expected) + "\n") 48 | }; 49 | console.log("pass".green + " " + test); 50 | }); 51 | }); 52 | 53 | function sort(a, b) { 54 | if (JSON.stringify(a) < JSON.stringify(b)) { 55 | return -1; 56 | } 57 | return 1; 58 | } 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # js-select 2 | 3 | js-select uses [js-traverse](https://github.com/substack/js-traverse) to traverse and modify JavaScript object nodes that match [JSONSelect](http://jsonselect.org/) selectors. 4 | 5 | ```javascript 6 | var people = { 7 | george: { 8 | age : 35, 9 | movie: "Repo Man" 10 | }, 11 | mary: { 12 | age: 15, 13 | movie: "Twilight" 14 | } 15 | }; 16 | ``` 17 | 18 | ### .forEach(fn) 19 | 20 | Iterates over all matching nodes in the object. The callback gets a special `this` context. See [js-traverse](https://github.com/substack/js-traverse) for all the things you can do to modify and inspect the node with this context. In addition, js-select adds a `this.matches()` which will test if the node matches a selector: 21 | 22 | ```javascript 23 | select(people).forEach(function(node) { 24 | if (this.matches(".mary > .movie")) { 25 | this.remove(); 26 | } 27 | }); 28 | ``` 29 | 30 | ### .nodes() 31 | 32 | Returns all matching nodes from the object. 33 | 34 | ```javascript 35 | select(people, ".age").nodes(); // [35, 15] 36 | ``` 37 | 38 | ### .remove() 39 | 40 | Removes matching elements from the original object. 41 | 42 | ```javascript 43 | select(people, ".age").remove(); 44 | ``` 45 | 46 | ### .update(fn) 47 | 48 | Updates all matching nodes using the given callback. 49 | 50 | ```javascript 51 | select(people, ".age").update(function(age) { 52 | return age - 5; 53 | }); 54 | ``` 55 | 56 | ### .condense() 57 | 58 | Reduces the original object down to only the matching elements (the hierarchy is maintained). 59 | 60 | ```javascript 61 | select(people, ".age").condense(); 62 | ``` 63 | 64 | ```javascript 65 | { 66 | george: { age: 35 }, 67 | mary: { age: 15 } 68 | } 69 | ``` 70 | 71 | ## Selectors 72 | 73 | js-select supports the following [JSONSelect](http://jsonselect.org/) selectors: 74 | 75 | ``` 76 | * 77 | type 78 | .key 79 | ancestor selector 80 | parent > selector 81 | sibling ~ selector 82 | selector1, selector2 83 | :root 84 | :nth-child(n) 85 | :nth-child(even) 86 | :nth-child(odd) 87 | :nth-last-child(n) 88 | :first-child 89 | :last-child 90 | :only-child 91 | :has(selector) 92 | :val("string") 93 | :contains("substring") 94 | ``` 95 | 96 | See [details](http://jsonselect.org/#docs/overview) on each selector, and [try them](http://jsonselect.org/#tryit) out on the JSONSelect website. 97 | 98 | ## Install 99 | 100 | For [node](http://nodejs.org), install with [npm](http://npmjs.org): 101 | 102 | ```bash 103 | npm install js-select 104 | ``` 105 | 106 | For the browser, download the select.js file or fetch the latest version from [npm](http://npmjs.org) and build a browser file using [browserify](https://github.com/substack/node-browserify): 107 | 108 | ```bash 109 | npm install browserify -g 110 | npm install js-select 111 | 112 | browserify --require js-select --outfile select.js 113 | ``` 114 | this will build a browser file with `require('js-select')` available. 115 | 116 | ## Propers 117 | 118 | Huge thanks to [@substack](http://github.com/substack) for the ingenious [js-traverse](https://github.com/substack/js-traverse) and [@lloyd](https://github.com/lloyd) for the ingenious [JSONSelect spec](http://http://jsonselect.org/) and [selector parser](http://search.npmjs.org/#/JSONSelect). -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var traverse = require("traverse"), 2 | JSONSelect = require("JSONSelect"); 3 | 4 | module.exports = function(obj, string) { 5 | var sels = parseSelectors(string); 6 | 7 | return { 8 | nodes: function() { 9 | var nodes = []; 10 | this.forEach(function(node) { 11 | nodes.push(node); 12 | }); 13 | return nodes; 14 | }, 15 | 16 | update: function(cb) { 17 | this.forEach(function(node) { 18 | this.update(typeof cb == "function" ? cb(node) : cb); 19 | }); 20 | return obj; 21 | }, 22 | 23 | remove: function() { 24 | this.forEach(function(node) { 25 | this.remove(); 26 | }) 27 | return obj; 28 | }, 29 | 30 | condense: function() { 31 | traverse(obj).forEach(function(node) { 32 | if (!this.parent) return; 33 | 34 | if (this.parent.keep) { 35 | this.keep = true; 36 | } else { 37 | var match = matchesAny(sels, this); 38 | this.keep = match; 39 | if (!match) { 40 | if (this.isLeaf) { 41 | this.remove(); 42 | } else { 43 | this.after(function() { 44 | if (this.keep_child) { 45 | this.parent.keep_child = true; 46 | } 47 | if (!this.keep && !this.keep_child) { 48 | this.remove(); 49 | } 50 | }); 51 | } 52 | } else { 53 | this.parent.keep_child = true; 54 | } 55 | } 56 | }); 57 | return obj; 58 | }, 59 | 60 | forEach: function(cb) { 61 | traverse(obj).forEach(function(node) { 62 | if (matchesAny(sels, this)) { 63 | this.matches = function(string) { 64 | return matchesAny(parseSelectors(string), this); 65 | }; 66 | // inherit context from js-traverse 67 | cb.call(this, node); 68 | } 69 | }); 70 | return obj; 71 | } 72 | }; 73 | } 74 | 75 | function parseSelectors(string) { 76 | var parsed = JSONSelect._parse(string || "*")[1]; 77 | return getSelectors(parsed); 78 | } 79 | 80 | function getSelectors(parsed) { 81 | if (parsed[0] == ",") { // "selector1, selector2" 82 | return parsed.slice(1); 83 | } 84 | return [parsed]; 85 | } 86 | 87 | function matchesAny(sels, context) { 88 | for (var i = 0; i < sels.length; i++) { 89 | if (matches(sels[i], context)) { 90 | return true; 91 | } 92 | } 93 | return false; 94 | } 95 | 96 | function matches(sel, context) { 97 | var path = context.parents.concat([context]), 98 | i = path.length - 1, 99 | j = sel.length - 1; 100 | 101 | // walk up the ancestors 102 | var must = true; 103 | while(j >= 0 && i >= 0) { 104 | var part = sel[j], 105 | context = path[i]; 106 | 107 | if (part == ">") { 108 | j--; 109 | must = true; 110 | continue; 111 | } 112 | 113 | if (matchesKey(part, context)) { 114 | j--; 115 | } 116 | else if (must) { 117 | return false; 118 | } 119 | 120 | i--; 121 | must = false; 122 | } 123 | return j == -1; 124 | } 125 | 126 | function matchesKey(part, context) { 127 | var key = context.key, 128 | node = context.node, 129 | parent = context.parent; 130 | 131 | if (part.id && key != part.id) { 132 | return false; 133 | } 134 | if (part.type) { 135 | var type = part.type; 136 | 137 | if (type == "null" && node !== null) { 138 | return false; 139 | } 140 | else if (type == "array" && !isArray(node)) { 141 | return false; 142 | } 143 | else if (type == "object" && (typeof node != "object" 144 | || node === null || isArray(node))) { 145 | return false; 146 | } 147 | else if ((type == "boolean" || type == "string" || type == "number") 148 | && type != typeof node) { 149 | return false; 150 | } 151 | } 152 | if (part.pf == ":nth-child") { 153 | var index = parseInt(key) + 1; 154 | if ((part.a == 0 && index !== part.b) // :nth-child(i) 155 | || (part.a == 1 && !(index >= -part.b)) // :nth-child(n) 156 | || (part.a == -1 && !(index <= part.b)) // :nth-child(-n + 1) 157 | || (part.a == 2 && index % 2 != part.b)) { // :nth-child(even) 158 | return false; 159 | } 160 | } 161 | if (part.pf == ":nth-last-child" 162 | && (!parent || key != parent.node.length - part.b)) { 163 | return false; 164 | } 165 | if (part.pc == ":only-child" 166 | && (!parent || parent.node.length != 1)) { 167 | return false; 168 | } 169 | if (part.pc == ":root" && key !== undefined) { 170 | return false; 171 | } 172 | if (part.has) { 173 | var sels = getSelectors(part.has[0]), 174 | match = false; 175 | traverse(node).forEach(function(child) { 176 | if (matchesAny(sels, this)) { 177 | match = true; 178 | } 179 | }); 180 | if (!match) { 181 | return false; 182 | } 183 | } 184 | if (part.expr) { 185 | var expr = part.expr, lhs = expr[0], op = expr[1], rhs = expr[2]; 186 | if (typeof node != "string" 187 | || (!lhs && op == "=" && node != rhs) // :val("str") 188 | || (!lhs && op == "*=" && node.indexOf(rhs) == -1)) { // :contains("substr") 189 | return false; 190 | } 191 | } 192 | return true; 193 | } 194 | 195 | var isArray = Array.isArray || function(obj) { 196 | return toString.call(obj) === '[object Array]'; 197 | } 198 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"), 2 | fs = require("fs"), 3 | traverse = require("traverse") 4 | select = require("../index"); 5 | 6 | var people = { 7 | "george": { 8 | age : 35, 9 | movies: [{ 10 | name: "Repo Man", 11 | stars: 5 12 | }] 13 | }, 14 | "mary": { 15 | age: 15, 16 | movies: [{ 17 | name: "Twilight", 18 | stars: 3 19 | }, 20 | { 21 | name: "Trudy", 22 | stars: 2 23 | }, 24 | { 25 | name: "The Fighter", 26 | stars: 4 27 | }] 28 | }, 29 | "chris" : { 30 | car: null, 31 | male: true 32 | } 33 | }; 34 | 35 | var people2, obj; 36 | 37 | assert.deepEqual(select(people, "*").nodes(), [{"george":{"age":35,"movies":[{"name":"Repo Man","stars":5}]},"mary":{"age":15,"movies":[{"name":"Twilight","stars":3},{"name":"Trudy","stars":2},{"name":"The Fighter","stars":4}]},"chris":{"car":null,"male":true}},{"age":35,"movies":[{"name":"Repo Man","stars":5}]},35,[{"name":"Repo Man","stars":5}],{"name":"Repo Man","stars":5},"Repo Man",5,{"age":15,"movies":[{"name":"Twilight","stars":3},{"name":"Trudy","stars":2},{"name":"The Fighter","stars":4}]},15,[{"name":"Twilight","stars":3},{"name":"Trudy","stars":2},{"name":"The Fighter","stars":4}],{"name":"Twilight","stars":3},"Twilight",3,{"name":"Trudy","stars":2},"Trudy",2,{"name":"The Fighter","stars":4},"The Fighter",4,{"car":null,"male":true},null,true]); 38 | assert.deepEqual(select(people, ".george").nodes(), [{"age":35,"movies":[{"name":"Repo Man","stars":5}]}]); 39 | assert.deepEqual(select(people, ".george .age").nodes(), [35]); 40 | assert.deepEqual(select(people, ".george .name").nodes(), ["Repo Man"]); 41 | assert.deepEqual(select(people, ".george *").nodes(), [35,[{"name":"Repo Man","stars":5}],{"name":"Repo Man","stars":5},"Repo Man",5]) 42 | 43 | assert.deepEqual(select(people, ".george > *").nodes(), [35,[{"name":"Repo Man","stars":5}]]); 44 | assert.deepEqual(select(people, ".george > .name").nodes(), []); 45 | 46 | assert.deepEqual(select(people, ":first-child").nodes(), [{"name":"Repo Man","stars":5},{"name":"Twilight","stars":3}]); 47 | assert.deepEqual(select(people, ":nth-child(1)").nodes(), select(people, ":first-child").nodes()); 48 | assert.deepEqual(select(people, ":nth-child(2)").nodes(), [{"name":"Trudy","stars":2}]); 49 | assert.deepEqual(select(people, ":nth-child(odd)").nodes(), [{"name":"Repo Man","stars":5},{"name":"Twilight","stars":3},{"name":"The Fighter","stars":4}]); 50 | assert.deepEqual(select(people, ":nth-child(even)").nodes(), [{"name":"Trudy","stars":2}]); 51 | 52 | assert.deepEqual(select(people, ":nth-child(-n+1)").nodes(), select(people, ":first-child").nodes()); 53 | assert.deepEqual(select(people, ":nth-child(-n+2)").nodes(), [{"name":"Repo Man","stars":5},{"name":"Twilight","stars":3},{"name":"Trudy","stars":2}]); 54 | assert.deepEqual(select(people, ":nth-child(n)").nodes(), [{"name":"Repo Man","stars":5},{"name":"Twilight","stars":3},{"name":"Trudy","stars":2},{"name":"The Fighter","stars":4}]); 55 | assert.deepEqual(select(people, ":nth-child(n-1)").nodes(), select(people, ":nth-child(n)").nodes()); 56 | assert.deepEqual(select(people, ":nth-child(n-2)").nodes(), [{"name":"Trudy","stars":2},{"name":"The Fighter","stars":4}]); 57 | 58 | assert.deepEqual(select(people, ":last-child").nodes(), [{"name":"Repo Man","stars":5},{"name":"The Fighter","stars":4}]); 59 | assert.deepEqual(select(people, ":nth-last-child(1)").nodes(), select(people, ":last-child").nodes()); 60 | assert.deepEqual(select(people, ":nth-last-child(2)").nodes(), [{"name":"Trudy","stars":2}]); 61 | assert.deepEqual(select(people, ":only-child").nodes(), [{"name":"Repo Man","stars":5}]); 62 | assert.deepEqual(select(people, ":root").nodes(),[{"george":{"age":35,"movies":[{"name":"Repo Man","stars":5}]},"mary":{"age":15,"movies":[{"name":"Twilight","stars":3},{"name":"Trudy","stars":2},{"name":"The Fighter","stars":4}]},"chris":{"car":null,"male":true}}]) 63 | 64 | assert.deepEqual(select(people, "string").nodes(),["Repo Man","Twilight","Trudy","The Fighter"]); 65 | assert.deepEqual(select(people, "number").nodes(),[35,5,15,3,2,4]); 66 | assert.deepEqual(select(people, "boolean").nodes(),[true]); 67 | assert.deepEqual(select(people, "object").nodes(),[{"george":{"age":35,"movies":[{"name":"Repo Man","stars":5}]},"mary":{"age":15,"movies":[{"name":"Twilight","stars":3},{"name":"Trudy","stars":2},{"name":"The Fighter","stars":4}]},"chris":{"car":null,"male":true}},{"age":35,"movies":[{"name":"Repo Man","stars":5}]},{"name":"Repo Man","stars":5},{"age":15,"movies":[{"name":"Twilight","stars":3},{"name":"Trudy","stars":2},{"name":"The Fighter","stars":4}]},{"name":"Twilight","stars":3},{"name":"Trudy","stars":2},{"name":"The Fighter","stars":4},{"car":null,"male":true}]); 68 | assert.deepEqual(select(people, "array").nodes(),[[{"name":"Repo Man","stars":5}],[{"name":"Twilight","stars":3},{"name":"Trudy","stars":2},{"name":"The Fighter","stars":4}]]); 69 | assert.deepEqual(select(people, "null").nodes(),[null]); 70 | 71 | assert.deepEqual(select(people, "number, string, boolean").nodes(), [35,"Repo Man",5,15,"Twilight",3,"Trudy",2,"The Fighter",4,true]) 72 | 73 | assert.deepEqual(select(people, ":has(.car) > .male").nodes(), [true]); 74 | assert.deepEqual(select(people, ".male ~ .car").nodes(), [null]) 75 | 76 | assert.deepEqual(select(people, ':val("Twilight")').nodes(), ["Twilight"]) 77 | assert.deepEqual(select(people, ':val("Twi")').nodes(), []) 78 | assert.deepEqual(select(people, ':contains("Twi")').nodes(), ["Twilight"]) 79 | assert.deepEqual(select(people, ':contains("weif")').nodes(), []) 80 | 81 | // invalid 82 | assert.deepEqual(select(people, ".hmmm").nodes(), []); 83 | assert.throws(function() { 84 | select(people, "afcjwiojwe9q28*C@!(# (!#R($R)))").nodes(); 85 | }); 86 | 87 | // update() 88 | people2 = traverse.clone(people); 89 | 90 | select(people2, ".age").update(function(age) { 91 | return age - 5; 92 | }) 93 | assert.deepEqual(select(people2, ".age").nodes(), [30, 10]); 94 | 95 | obj = select(people2, ".age").update(3) 96 | assert.deepEqual(select(people2, ".age").nodes(), [3, 3]); 97 | assert.deepEqual(obj, people2); 98 | 99 | // remove() 100 | people2 = traverse.clone(people); 101 | 102 | obj = select(people2, ".age").remove(); 103 | assert.deepEqual(select(people2, ".age").nodes(), []); 104 | assert.deepEqual(obj, people2); 105 | 106 | // condense() 107 | people2 = traverse.clone(people); 108 | select(people2, ".george").condense(); 109 | assert.deepEqual(people2, {"george": {age: 35, movies: [{name: "Repo Man", stars: 5}]}}); 110 | 111 | people2 = traverse.clone(people); 112 | select(people2, ".hmmm").condense(); 113 | assert.deepEqual(people2, {}); 114 | 115 | people2 = traverse.clone(people); 116 | obj = select(people2, ".stars").condense(); 117 | assert.deepEqual(people2, {"george": {movies: [{stars: 5}]}, "mary": {movies: [{stars: 3},{stars: 2},{stars: 4}]}}); 118 | assert.deepEqual(obj, people2); 119 | 120 | // forEach() 121 | people2 = traverse.clone(people); 122 | 123 | obj = select(people2, ".age").forEach(function(age) { 124 | this.update(age - 5); 125 | }) 126 | assert.deepEqual(select(people2, ".age").nodes(), [30, 10]); 127 | assert.deepEqual(obj, people2); 128 | 129 | 130 | // this.matches() 131 | people2 = traverse.clone(people); 132 | select(people2).forEach(function(node) { 133 | if (this.matches(".age")) { 134 | this.update(node + 10); 135 | } 136 | }); 137 | assert.deepEqual(select(people2, ".age").nodes(), [45, 25]) 138 | 139 | 140 | // bigger stuff 141 | var timeline = require("./timeline.js"); 142 | 143 | console.time("select time"); 144 | assert.equal(select(timeline, ".bug .id").nodes().length, 126); 145 | assert.equal(select(timeline, ".id").nodes().length, 141); 146 | assert.equal(select(timeline, ".comments .id").nodes().length, 115); 147 | assert.equal(select(timeline, ":nth-child(n-2)").nodes().length, 335); 148 | assert.equal(select(timeline, "object").nodes().length, 927); 149 | assert.equal(select(timeline, "*").nodes().length, 3281); 150 | console.timeEnd("select time") 151 | 152 | var sel = require("JSONSelect"); 153 | 154 | console.time("JSONSelect time") 155 | assert.equal(sel.match(".bug .id", timeline).length, 126); 156 | assert.equal(sel.match(".id", timeline).length, 141); 157 | assert.equal(sel.match(".comments .id", timeline).length, 115); 158 | assert.equal(sel.match(":nth-child(n-2)", timeline).length, 335); 159 | assert.equal(sel.match("object", timeline).length, 927); 160 | assert.equal(sel.match("*", timeline).length, 3281); 161 | console.timeEnd("JSONSelect time") 162 | -------------------------------------------------------------------------------- /select-min.js: -------------------------------------------------------------------------------- 1 | var select=function(){var c=function(j,f){var d=c.resolve(j,f||"/"),l=c.modules[d];if(!l)throw Error("Failed to resolve module "+j+", tried "+d);return(d=c.cache[d])?d.exports:l()};c.paths=[];c.modules={};c.cache={};c.extensions=[".js",".coffee"];c._core={assert:!0,events:!0,fs:!0,path:!0,vm:!0};c.resolve=function(j,f){function d(b){b=h.normalize(b);if(c.modules[b])return b;for(var a=0;a"==q)f--,r=!0;else{if(h(q,c))f--;else if(r){d=!1;break a}j--; 12 | r=!1}}d=-1==f}if(d)return!0}return!1}function h(b,e){var d=e.key,c=e.node,h=e.parent;if(b.id&&d!=b.id)return!1;if(b.type){var f=b.type;if("null"==f&&null!==c||"array"==f&&!g(c)||"object"==f&&("object"!=typeof c||null===c||g(c))||("boolean"==f||"string"==f||"number"==f)&&f!=typeof c)return!1}if(":nth-child"==b.pf&&(f=parseInt(d)+1,0==b.a&&f!==b.b||1==b.a&&!(f>=-b.b)||-1==b.a&&!(f<=b.b)||2==b.a&&f%2!=b.b)||":nth-last-child"==b.pf&&(!h||d!=h.node.length-b.b)||":only-child"==b.pc&&(!h||1!=h.node.length)|| 13 | ":root"==b.pc&&void 0!==d)return!1;if(b.has){var j=","==b.has[0][0]?b.has[0].slice(1):[b.has[0]],p=!1;a(c).forEach(function(){l(j,this)&&(p=!0)});if(!p)return!1}return b.expr&&(f=b.expr,d=f[0],h=f[1],f=f[2],"string"!=typeof c||!d&&"="==h&&c!=f||!d&&"*="==h&&-1==c.indexOf(f))?!1:!0}var a=c("traverse"),e=c("JSONSelect");f.exports=function(b,e){var g=d(e);return{nodes:function(){var a=[];this.forEach(function(b){a.push(b)});return a},update:function(a){this.forEach(function(b){this.update("function"== 14 | typeof a?a(b):a)})},remove:function(){this.forEach(function(){this.remove()})},condense:function(){a(b).forEach(function(){if(this.parent)if(this.parent.keep)this.keep=!0;else{var a=l(g,this);(this.keep=a)?this.parent.keep_child=!0:this.isLeaf?this.remove():this.after(function(){this.keep_child&&(this.parent.keep_child=!0);!this.keep&&!this.keep_child&&this.remove()})}})},forEach:function(e){a(b).forEach(function(a){l(g,this)&&(this.matches=function(a){return l(d(a),this)},e.call(this,a))})}}};var g= 15 | Array.isArray||function(a){return"[object Array]"===toString.call(a)}});c.define("/node_modules/traverse/package.json",function(c,f){f.exports={main:"./index"}});c.define("/node_modules/traverse/index.js",function(c,f){function d(a){if(!(this instanceof d))return new d(a);this.value=a}function l(a,e,g){var b=[],d=[],c=!0;return function x(a){var f=g?h(a):a,l,j,q,v,n=!0,i={node:f,node_:a,path:[].concat(b),parent:d[d.length-1],parents:d,key:b.slice(-1)[0],isRoot:0===b.length,level:b.length,circular:null, 16 | update:function(a,b){i.isRoot||(i.parent.node[i.key]=a);i.node=a;b&&(n=!1)},"delete":function(){delete i.parent.node[i.key]},remove:function(){Array.isArray(i.parent.node)?i.parent.node.splice(i.key,1):delete i.parent.node[i.key]},keys:null,before:function(a){l=a},after:function(a){j=a},pre:function(a){q=a},post:function(a){v=a},stop:function(){c=!1},block:function(){n=!1}};if(!c)return i;if("object"===typeof f&&null!==f){i.keys=Object.keys(f);i.isLeaf=0==i.keys.length;for(f=0;f=w[f[0][1]][0];)f=f[0];f[0]=[e,c[1],f[0]]}return[d,l]},t=function(a,c){function d(a){return"object"!==typeof a||null===a?a:"("=== 26 | a[0]?d(a[1]):[d(a[0]),a[1],d(a[2])]}var e=b(a,c?c:0);return[e[0],d(e[1])]},o=function(a,c){if(void 0===a)return c;if(null===a||"object"!==typeof a)return a;var b=o(a[0],c),d=o(a[2],c);return w[a[1]][1](b,d)},y=function(c,b,d,e){d||(e={});var f=[],g,l;for(b||(b=0);;){var m;m=c;var i=b,b=i,j={},k=a(m,i);k&&" "===k[1]&&(b=i=k[0],k=a(m,i));k&&k[1]===n.typ?(j.type=k[2],k=a(m,i=k[0])):k&&"*"===k[1]&&(k=a(m,i=k[0]));for(;void 0!==k;){if(k[1]===n.ide)j.id&&h("nmi",k[1]),j.id=k[2];else if(k[1]===n.psc)(j.pc|| 27 | j.pf)&&h("mpc",k[1]),":first-child"===k[2]?(j.pf=":nth-child",j.a=0,j.b=1):":last-child"===k[2]?(j.pf=":nth-last-child",j.a=0,j.b=1):j.pc=k[2];else if(k[1]===n.psf)":val"===k[2]||":contains"===k[2]?(j.expr=[void 0,":val"===k[2]?"=":"*=",void 0],(k=a(m,k[0]))&&" "===k[1]&&(k=a(m,k[0])),(!k||"("!==k[1])&&h("pex",m),(k=a(m,k[0]))&&" "===k[1]&&(k=a(m,k[0])),(!k||k[1]!==n.str)&&h("sex",m),j.expr[2]=k[2],(k=a(m,k[0]))&&" "===k[1]&&(k=a(m,k[0])),(!k||")"!==k[1])&&h("epex",m)):":has"===k[2]?((k=a(m,k[0]))&& 28 | " "===k[1]&&(k=a(m,k[0])),(!k||"("!==k[1])&&h("pex",m),i=y(m,k[0],!0),k[0]=i[0],j.has||(j.has=[]),j.has.push(i[1])):":expr"===k[2]?(j.expr&&h("mexp",m),i=t(m,k[0]),k[0]=i[0],j.expr=i[1]):((j.pc||j.pf)&&h("mpc",m),j.pf=k[2],(i=A.exec(m.substr(k[0])))||h("mepf",m),i[5]?(j.a=2,j.b="odd"===i[5]?1:0):i[6]?(j.a=0,j.b=parseInt(i[6],10)):(j.a=parseInt((i[1]?i[1]:"+")+(i[2]?i[2]:"1"),10),j.b=i[3]?parseInt(i[3]+i[4],10):0),k[0]+=i[0].length);else break;k=a(m,i=k[0])}b===i&&h("se",m);m=[i,j];f.push(m[1]);(m= 29 | a(c,b=m[0]))&&" "===m[1]&&(m=a(c,b=m[0]));if(!m)break;if(">"===m[1]||"~"===m[1])"~"===m[1]&&(e.usesSiblingOp=!0),f.push(m[1]),b=m[0];else if(","===m[1])void 0===g?g=[",",f]:g.push(f),f=[],b=m[0];else if(")"===m[1]){d||h("ucp",m[1]);l=1;b=m[0];break}}d&&!l&&h("mcp",c);g&&g.push(f);var s;if(!d&&e.usesSiblingOp)if(c=g?g:f,","===c[0]){for(d=[","];sd||">"!=a[d-2])b=a.slice(0,d-1),b=b.concat([{has:[[{pc:":root"},">",a[d-1]]]},">"]),b=b.concat(a.slice(d+1)),c.push(b);if(1",a[d-1]]);b=b.concat(f,">",a.slice(d+1));c.push(b)}break}return d==a.length?a:1"===b[0]?b[1]:b[0],h=!0;if(g.type&&h){var h=g.type,i;null===a?i="null":(i=typeof a,"object"===i&&u(a)&&(i="array"));h=h===i}g.id&&(h=h&&g.id===c);h&&g.pf&&(":nth-last-child"===g.pf?d=e-d:d++,0===g.a?h=g.b===d:(c=(d-g.b)%g.a,h=!c&&0<=d*g.a+g.b));if(h&&g.has){d=function(){throw 42;};for(c=0;c"!==b[0]&&":root"!==b[0].pc&&f.push(b);h&&(">"===b[0]?2\\)\\(])|(string|boolean|null|array|object|number)|(:(?:root|first-child|last-child|only-child))|(:(?:nth-child|nth-last-child|has|expr|val|contains))|(:\\w+)|(?:(\\.)?(\\"(?:[^\\\\\\"]|\\\\[^\\"])*\\"))|(\\")|\\.((?:[_a-zA-Z]|[^\\0-\\0177]|\\\\[^\\r\\n\\f0-9a-fA-F])(?:[_a-zA-Z0-9\\-]|[^\\u0000-\\u0177]|(?:\\\\[^\\r\\n\\f0-9a-fA-F]))*))'), 35 | A=/^\s*\(\s*(?:([+\-]?)([0-9]*)n\s*(?:([+\-])\s*([0-9]))?|(odd|even)|([+\-]?[0-9]+))\s*\)/,B=RegExp('^\\s*(?:(true|false|null)|(-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)|("(?:[^\\]|\\[^"])*")|(x)|(&&|\\|\\||[\\$\\^<>!\\*]=|[=+\\-*/%<>])|([\\(\\)]))'),w={"*":[9,function(a,b){return a*b}],"/":[9,function(a,b){return a/b}],"%":[9,function(a,b){return a%b}],"+":[7,function(a,b){return a+b}],"-":[7,function(a,b){return a-b}],"<=":[5,function(a,b){return e(a,"number")&&e(b,"number")&&a<=b}],">=":[5,function(a, 36 | b){return e(a,"number")&&e(b,"number")&&a>=b}],"$=":[5,function(a,b){return e(a,"string")&&e(b,"string")&&a.lastIndexOf(b)===a.length-b.length}],"^=":[5,function(a,b){return e(a,"string")&&e(b,"string")&&0===a.indexOf(b)}],"*=":[5,function(a,b){return e(a,"string")&&e(b,"string")&&-1!==a.indexOf(b)}],">":[5,function(a,b){return e(a,"number")&&e(b,"number")&&a>b}],"<":[5,function(a,b){return e(a,"number")&&e(b,"number")&&a= 0; i--) { 102 | if (parts[i] === 'node_modules') continue; 103 | var dir = parts.slice(0, i + 1).join('/') + '/node_modules'; 104 | dirs.push(dir); 105 | } 106 | 107 | return dirs; 108 | } 109 | }; 110 | })(); 111 | 112 | require.alias = function (from, to) { 113 | var path = require.modules.path(); 114 | var res = null; 115 | try { 116 | res = require.resolve(from + '/package.json', '/'); 117 | } 118 | catch (err) { 119 | res = require.resolve(from, '/'); 120 | } 121 | var basedir = path.dirname(res); 122 | 123 | var keys = (Object.keys || function (obj) { 124 | var res = []; 125 | for (var key in obj) res.push(key); 126 | return res; 127 | })(require.modules); 128 | 129 | for (var i = 0; i < keys.length; i++) { 130 | var key = keys[i]; 131 | if (key.slice(0, basedir.length + 1) === basedir + '/') { 132 | var f = key.slice(basedir.length); 133 | require.modules[to + f] = require.modules[basedir + f]; 134 | } 135 | else if (key === basedir) { 136 | require.modules[to] = require.modules[basedir]; 137 | } 138 | } 139 | }; 140 | 141 | (function () { 142 | var process = {}; 143 | 144 | require.define = function (filename, fn) { 145 | if (require.modules.__browserify_process) { 146 | process = require.modules.__browserify_process(); 147 | } 148 | 149 | var dirname = require._core[filename] 150 | ? '' 151 | : require.modules.path().dirname(filename) 152 | ; 153 | 154 | var require_ = function (file) { 155 | var requiredModule = require(file, dirname); 156 | var cached = require.cache[require.resolve(file, dirname)]; 157 | 158 | if (cached && cached.parent === null) { 159 | cached.parent = module_; 160 | } 161 | 162 | return requiredModule; 163 | }; 164 | require_.resolve = function (name) { 165 | return require.resolve(name, dirname); 166 | }; 167 | require_.modules = require.modules; 168 | require_.define = require.define; 169 | require_.cache = require.cache; 170 | var module_ = { 171 | id : filename, 172 | filename: filename, 173 | exports : {}, 174 | loaded : false, 175 | parent: null 176 | }; 177 | 178 | require.modules[filename] = function () { 179 | require.cache[filename] = module_; 180 | fn.call( 181 | module_.exports, 182 | require_, 183 | module_, 184 | module_.exports, 185 | dirname, 186 | filename, 187 | process 188 | ); 189 | module_.loaded = true; 190 | return module_.exports; 191 | }; 192 | }; 193 | })(); 194 | 195 | 196 | require.define("path",function(require,module,exports,__dirname,__filename,process){function filter (xs, fn) { 197 | var res = []; 198 | for (var i = 0; i < xs.length; i++) { 199 | if (fn(xs[i], i, xs)) res.push(xs[i]); 200 | } 201 | return res; 202 | } 203 | 204 | // resolves . and .. elements in a path array with directory names there 205 | // must be no slashes, empty elements, or device names (c:\) in the array 206 | // (so also no leading and trailing slashes - it does not distinguish 207 | // relative and absolute paths) 208 | function normalizeArray(parts, allowAboveRoot) { 209 | // if the path tries to go above the root, `up` ends up > 0 210 | var up = 0; 211 | for (var i = parts.length; i >= 0; i--) { 212 | var last = parts[i]; 213 | if (last == '.') { 214 | parts.splice(i, 1); 215 | } else if (last === '..') { 216 | parts.splice(i, 1); 217 | up++; 218 | } else if (up) { 219 | parts.splice(i, 1); 220 | up--; 221 | } 222 | } 223 | 224 | // if the path is allowed to go above the root, restore leading ..s 225 | if (allowAboveRoot) { 226 | for (; up--; up) { 227 | parts.unshift('..'); 228 | } 229 | } 230 | 231 | return parts; 232 | } 233 | 234 | // Regex to split a filename into [*, dir, basename, ext] 235 | // posix version 236 | var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/; 237 | 238 | // path.resolve([from ...], to) 239 | // posix version 240 | exports.resolve = function() { 241 | var resolvedPath = '', 242 | resolvedAbsolute = false; 243 | 244 | for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) { 245 | var path = (i >= 0) 246 | ? arguments[i] 247 | : process.cwd(); 248 | 249 | // Skip empty and invalid entries 250 | if (typeof path !== 'string' || !path) { 251 | continue; 252 | } 253 | 254 | resolvedPath = path + '/' + resolvedPath; 255 | resolvedAbsolute = path.charAt(0) === '/'; 256 | } 257 | 258 | // At this point the path should be resolved to a full absolute path, but 259 | // handle relative paths to be safe (might happen when process.cwd() fails) 260 | 261 | // Normalize the path 262 | resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { 263 | return !!p; 264 | }), !resolvedAbsolute).join('/'); 265 | 266 | return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; 267 | }; 268 | 269 | // path.normalize(path) 270 | // posix version 271 | exports.normalize = function(path) { 272 | var isAbsolute = path.charAt(0) === '/', 273 | trailingSlash = path.slice(-1) === '/'; 274 | 275 | // Normalize the path 276 | path = normalizeArray(filter(path.split('/'), function(p) { 277 | return !!p; 278 | }), !isAbsolute).join('/'); 279 | 280 | if (!path && !isAbsolute) { 281 | path = '.'; 282 | } 283 | if (path && trailingSlash) { 284 | path += '/'; 285 | } 286 | 287 | return (isAbsolute ? '/' : '') + path; 288 | }; 289 | 290 | 291 | // posix version 292 | exports.join = function() { 293 | var paths = Array.prototype.slice.call(arguments, 0); 294 | return exports.normalize(filter(paths, function(p, index) { 295 | return p && typeof p === 'string'; 296 | }).join('/')); 297 | }; 298 | 299 | 300 | exports.dirname = function(path) { 301 | var dir = splitPathRe.exec(path)[1] || ''; 302 | var isWindows = false; 303 | if (!dir) { 304 | // No dirname 305 | return '.'; 306 | } else if (dir.length === 1 || 307 | (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) { 308 | // It is just a slash or a drive letter with a slash 309 | return dir; 310 | } else { 311 | // It is a full dirname, strip trailing slash 312 | return dir.substring(0, dir.length - 1); 313 | } 314 | }; 315 | 316 | 317 | exports.basename = function(path, ext) { 318 | var f = splitPathRe.exec(path)[2] || ''; 319 | // TODO: make this comparison case-insensitive on windows? 320 | if (ext && f.substr(-1 * ext.length) === ext) { 321 | f = f.substr(0, f.length - ext.length); 322 | } 323 | return f; 324 | }; 325 | 326 | 327 | exports.extname = function(path) { 328 | return splitPathRe.exec(path)[3] || ''; 329 | }; 330 | }); 331 | 332 | require.define("__browserify_process",function(require,module,exports,__dirname,__filename,process){var process = module.exports = {}; 333 | 334 | process.nextTick = (function () { 335 | var queue = []; 336 | var canPost = typeof window !== 'undefined' 337 | && window.postMessage && window.addEventListener 338 | ; 339 | 340 | if (canPost) { 341 | window.addEventListener('message', function (ev) { 342 | if (ev.source === window && ev.data === 'browserify-tick') { 343 | ev.stopPropagation(); 344 | if (queue.length > 0) { 345 | var fn = queue.shift(); 346 | fn(); 347 | } 348 | } 349 | }, true); 350 | } 351 | 352 | return function (fn) { 353 | if (canPost) { 354 | queue.push(fn); 355 | window.postMessage('browserify-tick', '*'); 356 | } 357 | else setTimeout(fn, 0); 358 | }; 359 | })(); 360 | 361 | process.title = 'browser'; 362 | process.browser = true; 363 | process.env = {}; 364 | process.argv = []; 365 | 366 | process.binding = function (name) { 367 | if (name === 'evals') return (require)('vm') 368 | else throw new Error('No such module. (Possibly not yet loaded)') 369 | }; 370 | 371 | (function () { 372 | var cwd = '/'; 373 | var path; 374 | process.cwd = function () { return cwd }; 375 | process.chdir = function (dir) { 376 | if (!path) path = require('path'); 377 | cwd = path.resolve(dir, cwd); 378 | }; 379 | })(); 380 | }); 381 | 382 | require.define("vm",function(require,module,exports,__dirname,__filename,process){module.exports = require("vm-browserify")}); 383 | 384 | require.define("/node_modules/vm-browserify/package.json",function(require,module,exports,__dirname,__filename,process){module.exports = {"main":"index.js"}}); 385 | 386 | require.define("/node_modules/vm-browserify/index.js",function(require,module,exports,__dirname,__filename,process){var Object_keys = function (obj) { 387 | if (Object.keys) return Object.keys(obj) 388 | else { 389 | var res = []; 390 | for (var key in obj) res.push(key) 391 | return res; 392 | } 393 | }; 394 | 395 | var forEach = function (xs, fn) { 396 | if (xs.forEach) return xs.forEach(fn) 397 | else for (var i = 0; i < xs.length; i++) { 398 | fn(xs[i], i, xs); 399 | } 400 | }; 401 | 402 | var Script = exports.Script = function NodeScript (code) { 403 | if (!(this instanceof Script)) return new Script(code); 404 | this.code = code; 405 | }; 406 | 407 | Script.prototype.runInNewContext = function (context) { 408 | if (!context) context = {}; 409 | 410 | var iframe = document.createElement('iframe'); 411 | if (!iframe.style) iframe.style = {}; 412 | iframe.style.display = 'none'; 413 | 414 | document.body.appendChild(iframe); 415 | 416 | var win = iframe.contentWindow; 417 | 418 | forEach(Object_keys(context), function (key) { 419 | win[key] = context[key]; 420 | }); 421 | 422 | if (!win.eval && win.execScript) { 423 | // win.eval() magically appears when this is called in IE: 424 | win.execScript('null'); 425 | } 426 | 427 | var res = win.eval(this.code); 428 | 429 | forEach(Object_keys(win), function (key) { 430 | context[key] = win[key]; 431 | }); 432 | 433 | document.body.removeChild(iframe); 434 | 435 | return res; 436 | }; 437 | 438 | Script.prototype.runInThisContext = function () { 439 | return eval(this.code); // maybe... 440 | }; 441 | 442 | Script.prototype.runInContext = function (context) { 443 | // seems to be just runInNewContext on magical context objects which are 444 | // otherwise indistinguishable from objects except plain old objects 445 | // for the parameter segfaults node 446 | return this.runInNewContext(context); 447 | }; 448 | 449 | forEach(Object_keys(Script.prototype), function (name) { 450 | exports[name] = Script[name] = function (code) { 451 | var s = Script(code); 452 | return s[name].apply(s, [].slice.call(arguments, 1)); 453 | }; 454 | }); 455 | 456 | exports.createScript = function (code) { 457 | return exports.Script(code); 458 | }; 459 | 460 | exports.createContext = Script.createContext = function (context) { 461 | // not really sure what this one does 462 | // seems to just make a shallow copy 463 | var copy = {}; 464 | if(typeof context === 'object') { 465 | forEach(Object_keys(context), function (key) { 466 | copy[key] = context[key]; 467 | }); 468 | } 469 | return copy; 470 | }; 471 | }); 472 | 473 | require.define("/package.json",function(require,module,exports,__dirname,__filename,process){module.exports = {"main":"./index"}}); 474 | 475 | require.define("js-select",function(require,module,exports,__dirname,__filename,process){var traverse = require("traverse"), 476 | JSONSelect = require("JSONSelect"); 477 | 478 | module.exports = function(obj, string) { 479 | var sels = parseSelectors(string); 480 | 481 | return { 482 | nodes: function() { 483 | var nodes = []; 484 | this.forEach(function(node) { 485 | nodes.push(node); 486 | }); 487 | return nodes; 488 | }, 489 | 490 | update: function(cb) { 491 | this.forEach(function(node) { 492 | this.update(typeof cb == "function" ? cb(node) : cb); 493 | }); 494 | }, 495 | 496 | remove: function() { 497 | this.forEach(function(node) { 498 | this.remove(); 499 | }) 500 | }, 501 | 502 | condense: function() { 503 | traverse(obj).forEach(function(node) { 504 | if (!this.parent) return; 505 | 506 | if (this.parent.keep) { 507 | this.keep = true; 508 | } else { 509 | var match = matchesAny(sels, this); 510 | this.keep = match; 511 | if (!match) { 512 | if (this.isLeaf) { 513 | this.remove(); 514 | } else { 515 | this.after(function() { 516 | if (this.keep_child) { 517 | this.parent.keep_child = true; 518 | } 519 | if (!this.keep && !this.keep_child) { 520 | this.remove(); 521 | } 522 | }); 523 | } 524 | } else { 525 | this.parent.keep_child = true; 526 | } 527 | } 528 | }); 529 | }, 530 | 531 | forEach: function(cb) { 532 | traverse(obj).forEach(function(node) { 533 | if (matchesAny(sels, this)) { 534 | this.matches = function(string) { 535 | return matchesAny(parseSelectors(string), this); 536 | }; 537 | // inherit context from js-traverse 538 | cb.call(this, node); 539 | } 540 | }); 541 | } 542 | }; 543 | } 544 | 545 | function parseSelectors(string) { 546 | var parsed = JSONSelect._parse(string || "*")[1]; 547 | return getSelectors(parsed); 548 | } 549 | 550 | function getSelectors(parsed) { 551 | if (parsed[0] == ",") { // "selector1, selector2" 552 | return parsed.slice(1); 553 | } 554 | return [parsed]; 555 | } 556 | 557 | function matchesAny(sels, context) { 558 | for (var i = 0; i < sels.length; i++) { 559 | if (matches(sels[i], context)) { 560 | return true; 561 | } 562 | } 563 | return false; 564 | } 565 | 566 | function matches(sel, context) { 567 | var path = context.parents.concat([context]), 568 | i = path.length - 1, 569 | j = sel.length - 1; 570 | 571 | // walk up the ancestors 572 | var must = true; 573 | while(j >= 0 && i >= 0) { 574 | var part = sel[j], 575 | context = path[i]; 576 | 577 | if (part == ">") { 578 | j--; 579 | must = true; 580 | continue; 581 | } 582 | 583 | if (matchesKey(part, context)) { 584 | j--; 585 | } 586 | else if (must) { 587 | return false; 588 | } 589 | 590 | i--; 591 | must = false; 592 | } 593 | return j == -1; 594 | } 595 | 596 | function matchesKey(part, context) { 597 | var key = context.key, 598 | node = context.node, 599 | parent = context.parent; 600 | 601 | if (part.id && key != part.id) { 602 | return false; 603 | } 604 | if (part.type) { 605 | var type = part.type; 606 | 607 | if (type == "null" && node !== null) { 608 | return false; 609 | } 610 | else if (type == "array" && !isArray(node)) { 611 | return false; 612 | } 613 | else if (type == "object" && (typeof node != "object" 614 | || node === null || isArray(node))) { 615 | return false; 616 | } 617 | else if ((type == "boolean" || type == "string" || type == "number") 618 | && type != typeof node) { 619 | return false; 620 | } 621 | } 622 | if (part.pf == ":nth-child") { 623 | var index = parseInt(key) + 1; 624 | if ((part.a == 0 && index !== part.b) // :nth-child(i) 625 | || (part.a == 1 && !(index >= -part.b)) // :nth-child(n) 626 | || (part.a == -1 && !(index <= part.b)) // :nth-child(-n + 1) 627 | || (part.a == 2 && index % 2 != part.b)) { // :nth-child(even) 628 | return false; 629 | } 630 | } 631 | if (part.pf == ":nth-last-child" 632 | && (!parent || key != parent.node.length - part.b)) { 633 | return false; 634 | } 635 | if (part.pc == ":only-child" 636 | && (!parent || parent.node.length != 1)) { 637 | return false; 638 | } 639 | if (part.pc == ":root" && key !== undefined) { 640 | return false; 641 | } 642 | if (part.has) { 643 | var sels = getSelectors(part.has[0]), 644 | match = false; 645 | traverse(node).forEach(function(child) { 646 | if (matchesAny(sels, this)) { 647 | match = true; 648 | } 649 | }); 650 | if (!match) { 651 | return false; 652 | } 653 | } 654 | if (part.expr) { 655 | var expr = part.expr, lhs = expr[0], op = expr[1], rhs = expr[2]; 656 | if (typeof node != "string" 657 | || (!lhs && op == "=" && node != rhs) // :val("str") 658 | || (!lhs && op == "*=" && node.indexOf(rhs) == -1)) { // :contains("substr") 659 | return false; 660 | } 661 | } 662 | return true; 663 | } 664 | 665 | var isArray = Array.isArray || function(obj) { 666 | return toString.call(obj) === '[object Array]'; 667 | } 668 | }); 669 | 670 | require.define("/node_modules/traverse/package.json",function(require,module,exports,__dirname,__filename,process){module.exports = {"main":"./index"}}); 671 | 672 | require.define("/node_modules/traverse/index.js",function(require,module,exports,__dirname,__filename,process){module.exports = Traverse; 673 | function Traverse (obj) { 674 | if (!(this instanceof Traverse)) return new Traverse(obj); 675 | this.value = obj; 676 | } 677 | 678 | Traverse.prototype.get = function (ps) { 679 | var node = this.value; 680 | for (var i = 0; i < ps.length; i ++) { 681 | var key = ps[i]; 682 | if (!Object.hasOwnProperty.call(node, key)) { 683 | node = undefined; 684 | break; 685 | } 686 | node = node[key]; 687 | } 688 | return node; 689 | }; 690 | 691 | Traverse.prototype.set = function (ps, value) { 692 | var node = this.value; 693 | for (var i = 0; i < ps.length - 1; i ++) { 694 | var key = ps[i]; 695 | if (!Object.hasOwnProperty.call(node, key)) node[key] = {}; 696 | node = node[key]; 697 | } 698 | node[ps[i]] = value; 699 | return value; 700 | }; 701 | 702 | Traverse.prototype.map = function (cb) { 703 | return walk(this.value, cb, true); 704 | }; 705 | 706 | Traverse.prototype.forEach = function (cb) { 707 | this.value = walk(this.value, cb, false); 708 | return this.value; 709 | }; 710 | 711 | Traverse.prototype.reduce = function (cb, init) { 712 | var skip = arguments.length === 1; 713 | var acc = skip ? this.value : init; 714 | this.forEach(function (x) { 715 | if (!this.isRoot || !skip) { 716 | acc = cb.call(this, acc, x); 717 | } 718 | }); 719 | return acc; 720 | }; 721 | 722 | Traverse.prototype.deepEqual = function (obj) { 723 | if (arguments.length !== 1) { 724 | throw new Error( 725 | 'deepEqual requires exactly one object to compare against' 726 | ); 727 | } 728 | 729 | var equal = true; 730 | var node = obj; 731 | 732 | this.forEach(function (y) { 733 | var notEqual = (function () { 734 | equal = false; 735 | //this.stop(); 736 | return undefined; 737 | }).bind(this); 738 | 739 | //if (node === undefined || node === null) return notEqual(); 740 | 741 | if (!this.isRoot) { 742 | /* 743 | if (!Object.hasOwnProperty.call(node, this.key)) { 744 | return notEqual(); 745 | } 746 | */ 747 | if (typeof node !== 'object') return notEqual(); 748 | node = node[this.key]; 749 | } 750 | 751 | var x = node; 752 | 753 | this.post(function () { 754 | node = x; 755 | }); 756 | 757 | var toS = function (o) { 758 | return Object.prototype.toString.call(o); 759 | }; 760 | 761 | if (this.circular) { 762 | if (Traverse(obj).get(this.circular.path) !== x) notEqual(); 763 | } 764 | else if (typeof x !== typeof y) { 765 | notEqual(); 766 | } 767 | else if (x === null || y === null || x === undefined || y === undefined) { 768 | if (x !== y) notEqual(); 769 | } 770 | else if (x.__proto__ !== y.__proto__) { 771 | notEqual(); 772 | } 773 | else if (x === y) { 774 | // nop 775 | } 776 | else if (typeof x === 'function') { 777 | if (x instanceof RegExp) { 778 | // both regexps on account of the __proto__ check 779 | if (x.toString() != y.toString()) notEqual(); 780 | } 781 | else if (x !== y) notEqual(); 782 | } 783 | else if (typeof x === 'object') { 784 | if (toS(y) === '[object Arguments]' 785 | || toS(x) === '[object Arguments]') { 786 | if (toS(x) !== toS(y)) { 787 | notEqual(); 788 | } 789 | } 790 | else if (x instanceof Date || y instanceof Date) { 791 | if (!(x instanceof Date) || !(y instanceof Date) 792 | || x.getTime() !== y.getTime()) { 793 | notEqual(); 794 | } 795 | } 796 | else { 797 | var kx = Object.keys(x); 798 | var ky = Object.keys(y); 799 | if (kx.length !== ky.length) return notEqual(); 800 | for (var i = 0; i < kx.length; i++) { 801 | var k = kx[i]; 802 | if (!Object.hasOwnProperty.call(y, k)) { 803 | notEqual(); 804 | } 805 | } 806 | } 807 | } 808 | }); 809 | 810 | return equal; 811 | }; 812 | 813 | Traverse.prototype.paths = function () { 814 | var acc = []; 815 | this.forEach(function (x) { 816 | acc.push(this.path); 817 | }); 818 | return acc; 819 | }; 820 | 821 | Traverse.prototype.nodes = function () { 822 | var acc = []; 823 | this.forEach(function (x) { 824 | acc.push(this.node); 825 | }); 826 | return acc; 827 | }; 828 | 829 | Traverse.prototype.clone = function () { 830 | var parents = [], nodes = []; 831 | 832 | return (function clone (src) { 833 | for (var i = 0; i < parents.length; i++) { 834 | if (parents[i] === src) { 835 | return nodes[i]; 836 | } 837 | } 838 | 839 | if (typeof src === 'object' && src !== null) { 840 | var dst = copy(src); 841 | 842 | parents.push(src); 843 | nodes.push(dst); 844 | 845 | Object.keys(src).forEach(function (key) { 846 | dst[key] = clone(src[key]); 847 | }); 848 | 849 | parents.pop(); 850 | nodes.pop(); 851 | return dst; 852 | } 853 | else { 854 | return src; 855 | } 856 | })(this.value); 857 | }; 858 | 859 | function walk (root, cb, immutable) { 860 | var path = []; 861 | var parents = []; 862 | var alive = true; 863 | 864 | return (function walker (node_) { 865 | var node = immutable ? copy(node_) : node_; 866 | var modifiers = {}; 867 | 868 | var keepGoing = true; 869 | 870 | var state = { 871 | node : node, 872 | node_ : node_, 873 | path : [].concat(path), 874 | parent : parents[parents.length - 1], 875 | parents : parents, 876 | key : path.slice(-1)[0], 877 | isRoot : path.length === 0, 878 | level : path.length, 879 | circular : null, 880 | update : function (x, stopHere) { 881 | if (!state.isRoot) { 882 | state.parent.node[state.key] = x; 883 | } 884 | state.node = x; 885 | if (stopHere) keepGoing = false; 886 | }, 887 | 'delete' : function () { 888 | delete state.parent.node[state.key]; 889 | }, 890 | remove : function () { 891 | if (Array.isArray(state.parent.node)) { 892 | state.parent.node.splice(state.key, 1); 893 | } 894 | else { 895 | delete state.parent.node[state.key]; 896 | } 897 | }, 898 | keys : null, 899 | before : function (f) { modifiers.before = f }, 900 | after : function (f) { modifiers.after = f }, 901 | pre : function (f) { modifiers.pre = f }, 902 | post : function (f) { modifiers.post = f }, 903 | stop : function () { alive = false }, 904 | block : function () { keepGoing = false } 905 | }; 906 | 907 | if (!alive) return state; 908 | 909 | if (typeof node === 'object' && node !== null) { 910 | state.keys = Object.keys(node); 911 | 912 | state.isLeaf = state.keys.length == 0; 913 | 914 | for (var i = 0; i < parents.length; i++) { 915 | if (parents[i].node_ === node_) { 916 | state.circular = parents[i]; 917 | break; 918 | } 919 | } 920 | } 921 | else { 922 | state.isLeaf = true; 923 | } 924 | 925 | state.notLeaf = !state.isLeaf; 926 | state.notRoot = !state.isRoot; 927 | 928 | // use return values to update if defined 929 | var ret = cb.call(state, state.node); 930 | if (ret !== undefined && state.update) state.update(ret); 931 | 932 | if (modifiers.before) modifiers.before.call(state, state.node); 933 | 934 | if (!keepGoing) return state; 935 | 936 | if (typeof state.node == 'object' 937 | && state.node !== null && !state.circular) { 938 | parents.push(state); 939 | 940 | state.keys.forEach(function (key, i) { 941 | path.push(key); 942 | 943 | if (modifiers.pre) modifiers.pre.call(state, state.node[key], key); 944 | 945 | var child = walker(state.node[key]); 946 | if (immutable && Object.hasOwnProperty.call(state.node, key)) { 947 | state.node[key] = child.node; 948 | } 949 | 950 | child.isLast = i == state.keys.length - 1; 951 | child.isFirst = i == 0; 952 | 953 | if (modifiers.post) modifiers.post.call(state, child); 954 | 955 | path.pop(); 956 | }); 957 | parents.pop(); 958 | } 959 | 960 | if (modifiers.after) modifiers.after.call(state, state.node); 961 | 962 | return state; 963 | })(root).node; 964 | } 965 | 966 | Object.keys(Traverse.prototype).forEach(function (key) { 967 | Traverse[key] = function (obj) { 968 | var args = [].slice.call(arguments, 1); 969 | var t = Traverse(obj); 970 | return t[key].apply(t, args); 971 | }; 972 | }); 973 | 974 | function copy (src) { 975 | if (typeof src === 'object' && src !== null) { 976 | var dst; 977 | 978 | if (Array.isArray(src)) { 979 | dst = []; 980 | } 981 | else if (src instanceof Date) { 982 | dst = new Date(src); 983 | } 984 | else if (src instanceof Boolean) { 985 | dst = new Boolean(src); 986 | } 987 | else if (src instanceof Number) { 988 | dst = new Number(src); 989 | } 990 | else if (src instanceof String) { 991 | dst = new String(src); 992 | } 993 | else { 994 | dst = Object.create(Object.getPrototypeOf(src)); 995 | } 996 | 997 | Object.keys(src).forEach(function (key) { 998 | dst[key] = src[key]; 999 | }); 1000 | return dst; 1001 | } 1002 | else return src; 1003 | } 1004 | }); 1005 | 1006 | require.define("/node_modules/JSONSelect/package.json",function(require,module,exports,__dirname,__filename,process){module.exports = {"main":"src/jsonselect"}}); 1007 | 1008 | require.define("/node_modules/JSONSelect/src/jsonselect.js",function(require,module,exports,__dirname,__filename,process){/*! Copyright (c) 2011, Lloyd Hilaiel, ISC License */ 1009 | /* 1010 | * This is the JSONSelect reference implementation, in javascript. 1011 | */ 1012 | (function(exports) { 1013 | 1014 | var // localize references 1015 | toString = Object.prototype.toString; 1016 | 1017 | function jsonParse(str) { 1018 | try { 1019 | if(JSON && JSON.parse){ 1020 | return JSON.parse(str); 1021 | } 1022 | return (new Function("return " + str))(); 1023 | } catch(e) { 1024 | te("ijs", e.message); 1025 | } 1026 | } 1027 | 1028 | // emitted error codes. 1029 | var errorCodes = { 1030 | "bop": "binary operator expected", 1031 | "ee": "expression expected", 1032 | "epex": "closing paren expected ')'", 1033 | "ijs": "invalid json string", 1034 | "mcp": "missing closing paren", 1035 | "mepf": "malformed expression in pseudo-function", 1036 | "mexp": "multiple expressions not allowed", 1037 | "mpc": "multiple pseudo classes (:xxx) not allowed", 1038 | "nmi": "multiple ids not allowed", 1039 | "pex": "opening paren expected '('", 1040 | "se": "selector expected", 1041 | "sex": "string expected", 1042 | "sra": "string required after '.'", 1043 | "uc": "unrecognized char", 1044 | "ucp": "unexpected closing paren", 1045 | "ujs": "unclosed json string", 1046 | "upc": "unrecognized pseudo class" 1047 | }; 1048 | 1049 | // throw an error message 1050 | function te(ec, context) { 1051 | throw new Error(errorCodes[ec] + ( context && " in '" + context + "'")); 1052 | } 1053 | 1054 | // THE LEXER 1055 | var toks = { 1056 | psc: 1, // pseudo class 1057 | psf: 2, // pseudo class function 1058 | typ: 3, // type 1059 | str: 4, // string 1060 | ide: 5 // identifiers (or "classes", stuff after a dot) 1061 | }; 1062 | 1063 | // The primary lexing regular expression in jsonselect 1064 | var pat = new RegExp( 1065 | "^(?:" + 1066 | // (1) whitespace 1067 | "([\\r\\n\\t\\ ]+)|" + 1068 | // (2) one-char ops 1069 | "([~*,>\\)\\(])|" + 1070 | // (3) types names 1071 | "(string|boolean|null|array|object|number)|" + 1072 | // (4) pseudo classes 1073 | "(:(?:root|first-child|last-child|only-child))|" + 1074 | // (5) pseudo functions 1075 | "(:(?:nth-child|nth-last-child|has|expr|val|contains))|" + 1076 | // (6) bogusly named pseudo something or others 1077 | "(:\\w+)|" + 1078 | // (7 & 8) identifiers and JSON strings 1079 | "(?:(\\.)?(\\\"(?:[^\\\\\\\"]|\\\\[^\\\"])*\\\"))|" + 1080 | // (8) bogus JSON strings missing a trailing quote 1081 | "(\\\")|" + 1082 | // (9) identifiers (unquoted) 1083 | "\\.((?:[_a-zA-Z]|[^\\0-\\0177]|\\\\[^\\r\\n\\f0-9a-fA-F])(?:[_a-zA-Z0-9\\-]|[^\\u0000-\\u0177]|(?:\\\\[^\\r\\n\\f0-9a-fA-F]))*)" + 1084 | ")" 1085 | ); 1086 | 1087 | // A regular expression for matching "nth expressions" (see grammar, what :nth-child() eats) 1088 | var nthPat = /^\s*\(\s*(?:([+\-]?)([0-9]*)n\s*(?:([+\-])\s*([0-9]))?|(odd|even)|([+\-]?[0-9]+))\s*\)/; 1089 | function lex(str, off) { 1090 | if (!off) off = 0; 1091 | var m = pat.exec(str.substr(off)); 1092 | if (!m) return undefined; 1093 | off+=m[0].length; 1094 | var a; 1095 | if (m[1]) a = [off, " "]; 1096 | else if (m[2]) a = [off, m[0]]; 1097 | else if (m[3]) a = [off, toks.typ, m[0]]; 1098 | else if (m[4]) a = [off, toks.psc, m[0]]; 1099 | else if (m[5]) a = [off, toks.psf, m[0]]; 1100 | else if (m[6]) te("upc", str); 1101 | else if (m[8]) a = [off, m[7] ? toks.ide : toks.str, jsonParse(m[8])]; 1102 | else if (m[9]) te("ujs", str); 1103 | else if (m[10]) a = [off, toks.ide, m[10].replace(/\\([^\r\n\f0-9a-fA-F])/g,"$1")]; 1104 | return a; 1105 | } 1106 | 1107 | // THE EXPRESSION SUBSYSTEM 1108 | 1109 | var exprPat = new RegExp( 1110 | // skip and don't capture leading whitespace 1111 | "^\\s*(?:" + 1112 | // (1) simple vals 1113 | "(true|false|null)|" + 1114 | // (2) numbers 1115 | "(-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?)|" + 1116 | // (3) strings 1117 | "(\"(?:[^\\]|\\[^\"])*\")|" + 1118 | // (4) the 'x' value placeholder 1119 | "(x)|" + 1120 | // (5) binops 1121 | "(&&|\\|\\||[\\$\\^<>!\\*]=|[=+\\-*/%<>])|" + 1122 | // (6) parens 1123 | "([\\(\\)])" + 1124 | ")" 1125 | ); 1126 | 1127 | function is(o, t) { return typeof o === t; } 1128 | var operators = { 1129 | '*': [ 9, function(lhs, rhs) { return lhs * rhs; } ], 1130 | '/': [ 9, function(lhs, rhs) { return lhs / rhs; } ], 1131 | '%': [ 9, function(lhs, rhs) { return lhs % rhs; } ], 1132 | '+': [ 7, function(lhs, rhs) { return lhs + rhs; } ], 1133 | '-': [ 7, function(lhs, rhs) { return lhs - rhs; } ], 1134 | '<=': [ 5, function(lhs, rhs) { return is(lhs, 'number') && is(rhs, 'number') && lhs <= rhs; } ], 1135 | '>=': [ 5, function(lhs, rhs) { return is(lhs, 'number') && is(rhs, 'number') && lhs >= rhs; } ], 1136 | '$=': [ 5, function(lhs, rhs) { return is(lhs, 'string') && is(rhs, 'string') && lhs.lastIndexOf(rhs) === lhs.length - rhs.length; } ], 1137 | '^=': [ 5, function(lhs, rhs) { return is(lhs, 'string') && is(rhs, 'string') && lhs.indexOf(rhs) === 0; } ], 1138 | '*=': [ 5, function(lhs, rhs) { return is(lhs, 'string') && is(rhs, 'string') && lhs.indexOf(rhs) !== -1; } ], 1139 | '>': [ 5, function(lhs, rhs) { return is(lhs, 'number') && is(rhs, 'number') && lhs > rhs; } ], 1140 | '<': [ 5, function(lhs, rhs) { return is(lhs, 'number') && is(rhs, 'number') && lhs < rhs; } ], 1141 | '=': [ 3, function(lhs, rhs) { return lhs === rhs; } ], 1142 | '!=': [ 3, function(lhs, rhs) { return lhs !== rhs; } ], 1143 | '&&': [ 2, function(lhs, rhs) { return lhs && rhs; } ], 1144 | '||': [ 1, function(lhs, rhs) { return lhs || rhs; } ] 1145 | }; 1146 | 1147 | function exprLex(str, off) { 1148 | var v, m = exprPat.exec(str.substr(off)); 1149 | if (m) { 1150 | off += m[0].length; 1151 | v = m[1] || m[2] || m[3] || m[5] || m[6]; 1152 | if (m[1] || m[2] || m[3]) return [off, 0, jsonParse(v)]; 1153 | else if (m[4]) return [off, 0, undefined]; 1154 | return [off, v]; 1155 | } 1156 | } 1157 | 1158 | function exprParse2(str, off) { 1159 | if (!off) off = 0; 1160 | // first we expect a value or a '(' 1161 | var l = exprLex(str, off), 1162 | lhs; 1163 | if (l && l[1] === '(') { 1164 | lhs = exprParse2(str, l[0]); 1165 | var p = exprLex(str, lhs[0]); 1166 | if (!p || p[1] !== ')') te('epex', str); 1167 | off = p[0]; 1168 | lhs = [ '(', lhs[1] ]; 1169 | } else if (!l || (l[1] && l[1] != 'x')) { 1170 | te("ee", str + " - " + ( l[1] && l[1] )); 1171 | } else { 1172 | lhs = ((l[1] === 'x') ? undefined : l[2]); 1173 | off = l[0]; 1174 | } 1175 | 1176 | // now we expect a binary operator or a ')' 1177 | var op = exprLex(str, off); 1178 | if (!op || op[1] == ')') return [off, lhs]; 1179 | else if (op[1] == 'x' || !op[1]) { 1180 | te('bop', str + " - " + ( op[1] && op[1] )); 1181 | } 1182 | 1183 | // tail recursion to fetch the rhs expression 1184 | var rhs = exprParse2(str, op[0]); 1185 | off = rhs[0]; 1186 | rhs = rhs[1]; 1187 | 1188 | // and now precedence! how shall we put everything together? 1189 | var v; 1190 | if (typeof rhs !== 'object' || rhs[0] === '(' || operators[op[1]][0] < operators[rhs[1]][0] ) { 1191 | v = [lhs, op[1], rhs]; 1192 | } 1193 | else { 1194 | v = rhs; 1195 | while (typeof rhs[0] === 'object' && rhs[0][0] != '(' && operators[op[1]][0] >= operators[rhs[0][1]][0]) { 1196 | rhs = rhs[0]; 1197 | } 1198 | rhs[0] = [lhs, op[1], rhs[0]]; 1199 | } 1200 | return [off, v]; 1201 | } 1202 | 1203 | function exprParse(str, off) { 1204 | function deparen(v) { 1205 | if (typeof v !== 'object' || v === null) return v; 1206 | else if (v[0] === '(') return deparen(v[1]); 1207 | else return [deparen(v[0]), v[1], deparen(v[2])]; 1208 | } 1209 | var e = exprParse2(str, off ? off : 0); 1210 | return [e[0], deparen(e[1])]; 1211 | } 1212 | 1213 | function exprEval(expr, x) { 1214 | if (expr === undefined) return x; 1215 | else if (expr === null || typeof expr !== 'object') { 1216 | return expr; 1217 | } 1218 | var lhs = exprEval(expr[0], x), 1219 | rhs = exprEval(expr[2], x); 1220 | return operators[expr[1]][1](lhs, rhs); 1221 | } 1222 | 1223 | // THE PARSER 1224 | 1225 | function parse(str, off, nested, hints) { 1226 | if (!nested) hints = {}; 1227 | 1228 | var a = [], am, readParen; 1229 | if (!off) off = 0; 1230 | 1231 | while (true) { 1232 | var s = parse_selector(str, off, hints); 1233 | a.push(s[1]); 1234 | s = lex(str, off = s[0]); 1235 | if (s && s[1] === " ") s = lex(str, off = s[0]); 1236 | if (!s) break; 1237 | // now we've parsed a selector, and have something else... 1238 | if (s[1] === ">" || s[1] === "~") { 1239 | if (s[1] === "~") hints.usesSiblingOp = true; 1240 | a.push(s[1]); 1241 | off = s[0]; 1242 | } else if (s[1] === ",") { 1243 | if (am === undefined) am = [ ",", a ]; 1244 | else am.push(a); 1245 | a = []; 1246 | off = s[0]; 1247 | } else if (s[1] === ")") { 1248 | if (!nested) te("ucp", s[1]); 1249 | readParen = 1; 1250 | off = s[0]; 1251 | break; 1252 | } 1253 | } 1254 | if (nested && !readParen) te("mcp", str); 1255 | if (am) am.push(a); 1256 | var rv; 1257 | if (!nested && hints.usesSiblingOp) { 1258 | rv = normalize(am ? am : a); 1259 | } else { 1260 | rv = am ? am : a; 1261 | } 1262 | return [off, rv]; 1263 | } 1264 | 1265 | function normalizeOne(sel) { 1266 | var sels = [], s; 1267 | for (var i = 0; i < sel.length; i++) { 1268 | if (sel[i] === '~') { 1269 | // `A ~ B` maps to `:has(:root > A) > B` 1270 | // `Z A ~ B` maps to `Z :has(:root > A) > B, Z:has(:root > A) > B` 1271 | // This first clause, takes care of the first case, and the first half of the latter case. 1272 | if (i < 2 || sel[i-2] != '>') { 1273 | s = sel.slice(0,i-1); 1274 | s = s.concat([{has:[[{pc: ":root"}, ">", sel[i-1]]]}, ">"]); 1275 | s = s.concat(sel.slice(i+1)); 1276 | sels.push(s); 1277 | } 1278 | // here we take care of the second half of above: 1279 | // (`Z A ~ B` maps to `Z :has(:root > A) > B, Z :has(:root > A) > B`) 1280 | // and a new case: 1281 | // Z > A ~ B maps to Z:has(:root > A) > B 1282 | if (i > 1) { 1283 | var at = sel[i-2] === '>' ? i-3 : i-2; 1284 | s = sel.slice(0,at); 1285 | var z = {}; 1286 | for (var k in sel[at]) if (sel[at].hasOwnProperty(k)) z[k] = sel[at][k]; 1287 | if (!z.has) z.has = []; 1288 | z.has.push([{pc: ":root"}, ">", sel[i-1]]); 1289 | s = s.concat(z, '>', sel.slice(i+1)); 1290 | sels.push(s); 1291 | } 1292 | break; 1293 | } 1294 | } 1295 | if (i == sel.length) return sel; 1296 | return sels.length > 1 ? [','].concat(sels) : sels[0]; 1297 | } 1298 | 1299 | function normalize(sels) { 1300 | if (sels[0] === ',') { 1301 | var r = [","]; 1302 | for (var i = i; i < sels.length; i++) { 1303 | var s = normalizeOne(s[i]); 1304 | r = r.concat(s[0] === "," ? s.slice(1) : s); 1305 | } 1306 | return r; 1307 | } else { 1308 | return normalizeOne(sels); 1309 | } 1310 | } 1311 | 1312 | function parse_selector(str, off, hints) { 1313 | var soff = off; 1314 | var s = { }; 1315 | var l = lex(str, off); 1316 | // skip space 1317 | if (l && l[1] === " ") { soff = off = l[0]; l = lex(str, off); } 1318 | if (l && l[1] === toks.typ) { 1319 | s.type = l[2]; 1320 | l = lex(str, (off = l[0])); 1321 | } else if (l && l[1] === "*") { 1322 | // don't bother representing the universal sel, '*' in the 1323 | // parse tree, cause it's the default 1324 | l = lex(str, (off = l[0])); 1325 | } 1326 | 1327 | // now support either an id or a pc 1328 | while (true) { 1329 | if (l === undefined) { 1330 | break; 1331 | } else if (l[1] === toks.ide) { 1332 | if (s.id) te("nmi", l[1]); 1333 | s.id = l[2]; 1334 | } else if (l[1] === toks.psc) { 1335 | if (s.pc || s.pf) te("mpc", l[1]); 1336 | // collapse first-child and last-child into nth-child expressions 1337 | if (l[2] === ":first-child") { 1338 | s.pf = ":nth-child"; 1339 | s.a = 0; 1340 | s.b = 1; 1341 | } else if (l[2] === ":last-child") { 1342 | s.pf = ":nth-last-child"; 1343 | s.a = 0; 1344 | s.b = 1; 1345 | } else { 1346 | s.pc = l[2]; 1347 | } 1348 | } else if (l[1] === toks.psf) { 1349 | if (l[2] === ":val" || l[2] === ":contains") { 1350 | s.expr = [ undefined, l[2] === ":val" ? "=" : "*=", undefined]; 1351 | // any amount of whitespace, followed by paren, string, paren 1352 | l = lex(str, (off = l[0])); 1353 | if (l && l[1] === " ") l = lex(str, off = l[0]); 1354 | if (!l || l[1] !== "(") te("pex", str); 1355 | l = lex(str, (off = l[0])); 1356 | if (l && l[1] === " ") l = lex(str, off = l[0]); 1357 | if (!l || l[1] !== toks.str) te("sex", str); 1358 | s.expr[2] = l[2]; 1359 | l = lex(str, (off = l[0])); 1360 | if (l && l[1] === " ") l = lex(str, off = l[0]); 1361 | if (!l || l[1] !== ")") te("epex", str); 1362 | } else if (l[2] === ":has") { 1363 | // any amount of whitespace, followed by paren 1364 | l = lex(str, (off = l[0])); 1365 | if (l && l[1] === " ") l = lex(str, off = l[0]); 1366 | if (!l || l[1] !== "(") te("pex", str); 1367 | var h = parse(str, l[0], true); 1368 | l[0] = h[0]; 1369 | if (!s.has) s.has = []; 1370 | s.has.push(h[1]); 1371 | } else if (l[2] === ":expr") { 1372 | if (s.expr) te("mexp", str); 1373 | var e = exprParse(str, l[0]); 1374 | l[0] = e[0]; 1375 | s.expr = e[1]; 1376 | } else { 1377 | if (s.pc || s.pf ) te("mpc", str); 1378 | s.pf = l[2]; 1379 | var m = nthPat.exec(str.substr(l[0])); 1380 | if (!m) te("mepf", str); 1381 | if (m[5]) { 1382 | s.a = 2; 1383 | s.b = (m[5] === "odd") ? 1 : 0; 1384 | } else if (m[6]) { 1385 | s.a = 0; 1386 | s.b = parseInt(m[6], 10); 1387 | } else { 1388 | s.a = parseInt((m[1] ? m[1] : "+") + (m[2] ? m[2] : "1"),10); 1389 | s.b = m[3] ? parseInt(m[3] + m[4],10) : 0; 1390 | } 1391 | l[0] += m[0].length; 1392 | } 1393 | } else { 1394 | break; 1395 | } 1396 | l = lex(str, (off = l[0])); 1397 | } 1398 | 1399 | // now if we didn't actually parse anything it's an error 1400 | if (soff === off) te("se", str); 1401 | 1402 | return [off, s]; 1403 | } 1404 | 1405 | // THE EVALUATOR 1406 | 1407 | function isArray(o) { 1408 | return Array.isArray ? Array.isArray(o) : 1409 | toString.call(o) === "[object Array]"; 1410 | } 1411 | 1412 | function mytypeof(o) { 1413 | if (o === null) return "null"; 1414 | var to = typeof o; 1415 | if (to === "object" && isArray(o)) to = "array"; 1416 | return to; 1417 | } 1418 | 1419 | function mn(node, sel, id, num, tot) { 1420 | var sels = []; 1421 | var cs = (sel[0] === ">") ? sel[1] : sel[0]; 1422 | var m = true, mod; 1423 | if (cs.type) m = m && (cs.type === mytypeof(node)); 1424 | if (cs.id) m = m && (cs.id === id); 1425 | if (m && cs.pf) { 1426 | if (cs.pf === ":nth-last-child") num = tot - num; 1427 | else num++; 1428 | if (cs.a === 0) { 1429 | m = cs.b === num; 1430 | } else { 1431 | mod = ((num - cs.b) % cs.a); 1432 | 1433 | m = (!mod && ((num*cs.a + cs.b) >= 0)); 1434 | } 1435 | } 1436 | if (m && cs.has) { 1437 | // perhaps we should augment forEach to handle a return value 1438 | // that indicates "client cancels traversal"? 1439 | var bail = function() { throw 42; }; 1440 | for (var i = 0; i < cs.has.length; i++) { 1441 | try { 1442 | forEach(cs.has[i], node, bail); 1443 | } catch (e) { 1444 | if (e === 42) continue; 1445 | } 1446 | m = false; 1447 | break; 1448 | } 1449 | } 1450 | if (m && cs.expr) { 1451 | m = exprEval(cs.expr, node); 1452 | } 1453 | // should we repeat this selector for descendants? 1454 | if (sel[0] !== ">" && sel[0].pc !== ":root") sels.push(sel); 1455 | 1456 | if (m) { 1457 | // is there a fragment that we should pass down? 1458 | if (sel[0] === ">") { if (sel.length > 2) { m = false; sels.push(sel.slice(2)); } } 1459 | else if (sel.length > 1) { m = false; sels.push(sel.slice(1)); } 1460 | } 1461 | 1462 | return [m, sels]; 1463 | } 1464 | 1465 | function forEach(sel, obj, fun, id, num, tot) { 1466 | var a = (sel[0] === ",") ? sel.slice(1) : [sel], 1467 | a0 = [], 1468 | call = false, 1469 | i = 0, j = 0, k, x; 1470 | for (i = 0; i < a.length; i++) { 1471 | x = mn(obj, a[i], id, num, tot); 1472 | if (x[0]) { 1473 | call = true; 1474 | } 1475 | for (j = 0; j < x[1].length; j++) { 1476 | a0.push(x[1][j]); 1477 | } 1478 | } 1479 | if (a0.length && typeof obj === "object") { 1480 | if (a0.length >= 1) { 1481 | a0.unshift(","); 1482 | } 1483 | if (isArray(obj)) { 1484 | for (i = 0; i < obj.length; i++) { 1485 | forEach(a0, obj[i], fun, undefined, i, obj.length); 1486 | } 1487 | } else { 1488 | for (k in obj) { 1489 | if (obj.hasOwnProperty(k)) { 1490 | forEach(a0, obj[k], fun, k); 1491 | } 1492 | } 1493 | } 1494 | } 1495 | if (call && fun) { 1496 | fun(obj); 1497 | } 1498 | } 1499 | 1500 | function match(sel, obj) { 1501 | var a = []; 1502 | forEach(sel, obj, function(x) { 1503 | a.push(x); 1504 | }); 1505 | return a; 1506 | } 1507 | 1508 | function compile(sel) { 1509 | return { 1510 | sel: parse(sel)[1], 1511 | match: function(obj){ 1512 | return match(this.sel, obj); 1513 | }, 1514 | forEach: function(obj, fun) { 1515 | return forEach(this.sel, obj, fun); 1516 | } 1517 | }; 1518 | } 1519 | 1520 | exports._lex = lex; 1521 | exports._parse = parse; 1522 | exports.match = function (sel, obj) { 1523 | return compile(sel).match(obj); 1524 | }; 1525 | exports.forEach = function(sel, obj, fun) { 1526 | return compile(sel).forEach(obj, fun); 1527 | }; 1528 | exports.compile = compile; 1529 | })(typeof exports === "undefined" ? (window.JSONSelect = {}) : exports); 1530 | }); 1531 | 1532 | return require('js-select'); 1533 | })(); -------------------------------------------------------------------------------- /test/timeline.js: -------------------------------------------------------------------------------- 1 | module.exports = [{"bug":{"history":[{"changes":[{"removed":"","added":"gmealer@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/gmealer@mozilla.com","name":"gmealer@mozilla.com"},"change_time":"2011-07-19T22:35:56Z"},{"changes":[{"removed":"NEW","added":"RESOLVED","field_name":"status"},{"removed":"","added":"WONTFIX","field_name":"resolution"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/fayearthur+bugs@gmail.com","name":"fayearthur+bugs@gmail.com"},"change_time":"2011-07-19T22:24:59Z"},{"changes":[{"removed":"","added":"fayearthur+bugs@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/fayearthur+bugs@gmail.com","name":"fayearthur+bugs@gmail.com"},"change_time":"2011-07-13T19:49:06Z"},{"changes":[{"removed":"","added":"hskupin@gmail.com, stomlinson@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-07-13T19:11:32Z"},{"changes":[{"removed":"","added":"ctalbert@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-13T18:43:17Z"}],"summary":"Adding isNumber, isFunction, isString, isArray and isObject to assert.js","last_change_time":"2011-07-19T22:35:56Z","comments":[{"is_private":false,"creator":{"real_name":"Geo Mealer [:geo]","name":"gmealer"},"text":"","id":5600392,"creation_time":"2011-07-19T22:35:56Z"},{"is_private":false,"creator":{"real_name":"Heather Arthur [:harth]","name":"fayearthur+bugs"},"text":"","id":5600359,"creation_time":"2011-07-19T22:24:59Z"},{"is_private":false,"creator":{"real_name":"Heather Arthur [:harth]","name":"fayearthur+bugs"},"text":"","id":5589849,"creation_time":"2011-07-13T20:24:38Z"},{"is_private":false,"creator":{"real_name":"Shane Tomlinson","name":"stomlinson"},"text":"","id":5589791,"creation_time":"2011-07-13T19:59:43Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5589782,"creation_time":"2011-07-13T19:56:44Z"},{"is_private":false,"creator":{"real_name":"Heather Arthur [:harth]","name":"fayearthur+bugs"},"text":"","id":5589758,"creation_time":"2011-07-13T19:49:06Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5589591,"creation_time":"2011-07-13T18:42:07Z"}],"id":671367},"events":[{"time":"2011-07-19T22:35:56Z","changeset":{"changes":[{"removed":"","added":"gmealer@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/gmealer@mozilla.com","name":"gmealer@mozilla.com"},"change_time":"2011-07-19T22:35:56Z"}},{"time":"2011-07-19T22:35:56Z","comment":{"is_private":false,"creator":{"real_name":"Geo Mealer [:geo]","name":"gmealer"},"text":"","id":5600392,"creation_time":"2011-07-19T22:35:56Z"}},{"time":"2011-07-19T22:24:59Z","changeset":{"changes":[{"removed":"NEW","added":"RESOLVED","field_name":"status"},{"removed":"","added":"WONTFIX","field_name":"resolution"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/fayearthur+bugs@gmail.com","name":"fayearthur+bugs@gmail.com"},"change_time":"2011-07-19T22:24:59Z"}},{"time":"2011-07-19T22:24:59Z","comment":{"is_private":false,"creator":{"real_name":"Heather Arthur [:harth]","name":"fayearthur+bugs"},"text":"","id":5600359,"creation_time":"2011-07-19T22:24:59Z"}}]},{"bug":{"history":[{"changes":[{"removed":"","added":"ctalbert@mozilla.com, fayearthur+bugs@gmail.com, jhammel@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-19T20:22:11Z"}],"summary":"mozmill \"--profile\" option not working with relative path","last_change_time":"2011-07-19T20:46:19Z","comments":[{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5600020,"creation_time":"2011-07-19T20:46:19Z"},{"is_private":false,"creator":{"real_name":"Marc-Aurèle DARCHE","name":"mozdev"},"text":"","id":5599999,"creation_time":"2011-07-19T20:39:07Z"},{"is_private":false,"creator":{"real_name":"Marc-Aurèle DARCHE","name":"mozdev"},"text":"","id":5599848,"creation_time":"2011-07-19T19:29:35Z"}],"id":672605},"events":[{"time":"2011-07-19T20:46:19Z","comment":{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5600020,"creation_time":"2011-07-19T20:46:19Z"}},{"time":"2011-07-19T20:39:07Z","comment":{"is_private":false,"creator":{"real_name":"Marc-Aurèle DARCHE","name":"mozdev"},"text":"","id":5599999,"creation_time":"2011-07-19T20:39:07Z"}},{"time":"2011-07-19T20:22:11Z","changeset":{"changes":[{"removed":"","added":"ctalbert@mozilla.com, fayearthur+bugs@gmail.com, jhammel@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-19T20:22:11Z"}},{"time":"2011-07-19T19:29:35Z","comment":{"is_private":false,"creator":{"real_name":"Marc-Aurèle DARCHE","name":"mozdev"},"text":"","id":5599848,"creation_time":"2011-07-19T19:29:35Z"}}]},{"bug":{"history":[{"changes":[{"removed":"","added":"ehsan@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ehsan@mozilla.com","name":"ehsan@mozilla.com"},"change_time":"2011-07-19T20:37:46Z"},{"changes":[{"removed":"","added":"fayearthur+bugs@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-07-19T17:37:11Z"},{"changes":[{"removed":"","added":"ctalbert@mozilla.com, jhammel@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-07-19T17:35:58Z"},{"changes":[{"removed":"","added":"ted.mielczarek@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ted.mielczarek@gmail.com","name":"ted.mielczarek@gmail.com"},"change_time":"2011-07-18T12:00:25Z"},{"changes":[{"removed":"","added":"bmo@edmorley.co.uk","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/bmo@edmorley.co.uk","name":"bmo@edmorley.co.uk"},"change_time":"2011-07-17T11:20:51Z"},{"changes":[{"removed":"","added":"bzbarsky@mit.edu","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/bzbarsky@mit.edu","name":"bzbarsky@mit.edu"},"change_time":"2011-07-14T03:29:52Z"},{"changes":[{"removed":"","added":"dmandelin@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/dmandelin@mozilla.com","name":"dmandelin@mozilla.com"},"change_time":"2011-07-14T00:27:21Z"},{"changes":[{"removed":"","added":"kairo@kairo.at","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/kairo@kairo.at","name":"kairo@kairo.at"},"change_time":"2011-07-14T00:04:16Z"},{"changes":[{"removed":"","added":"gavin.sharp@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/gavin.sharp@gmail.com","name":"gavin.sharp@gmail.com"},"change_time":"2011-07-13T23:17:24Z"},{"changes":[{"removed":"","added":"anygregor@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/anygregor@gmail.com","name":"anygregor@gmail.com"},"change_time":"2011-07-13T19:57:34Z"},{"changes":[{"removed":"","added":"luke@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/luke@mozilla.com","name":"luke@mozilla.com"},"change_time":"2011-07-13T18:53:42Z"},{"changes":[{"removed":"","added":"sphink@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/sphink@gmail.com","name":"sphink@gmail.com"},"change_time":"2011-07-13T18:23:30Z"},{"changes":[{"removed":"","added":"davemgarrett@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/davemgarrett@gmail.com","name":"davemgarrett@gmail.com"},"change_time":"2011-07-13T18:21:27Z"},{"changes":[{"removed":"","added":"khuey@kylehuey.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/khuey@kylehuey.com","name":"khuey@kylehuey.com"},"change_time":"2011-07-13T18:21:08Z"}],"summary":"Split chrome into multiple compartments for better accounting of JS memory used by chrome code (and add-ons)","last_change_time":"2011-07-19T20:37:46Z","comments":[{"is_private":false,"creator":{"real_name":"Ehsan Akhgari [:ehsan]","name":"ehsan"},"text":"","id":5599990,"creation_time":"2011-07-19T20:37:46Z"},{"is_private":false,"creator":{"real_name":"Gregor Wagner","name":"anygregor"},"text":"","id":5589947,"creation_time":"2011-07-13T21:04:28Z"},{"is_private":false,"creator":{"real_name":"Andreas Gal :gal","name":"gal"},"text":"","id":5589879,"creation_time":"2011-07-13T20:39:32Z"},{"is_private":false,"creator":{"real_name":"Gregor Wagner","name":"anygregor"},"text":"","id":5589812,"creation_time":"2011-07-13T20:07:18Z"},{"is_private":false,"creator":{"real_name":"Luke Wagner [:luke]","name":"luke"},"text":"","id":5589801,"creation_time":"2011-07-13T20:03:36Z"},{"is_private":false,"creator":{"real_name":"Gregor Wagner","name":"anygregor"},"text":"","id":5589787,"creation_time":"2011-07-13T19:57:34Z"},{"is_private":false,"creator":{"real_name":"Ehsan Akhgari [:ehsan]","name":"ehsan"},"text":"","id":5589485,"creation_time":"2011-07-13T18:15:17Z"}],"id":671352},"events":[{"time":"2011-07-19T20:37:46Z","changeset":{"changes":[{"removed":"","added":"ehsan@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ehsan@mozilla.com","name":"ehsan@mozilla.com"},"change_time":"2011-07-19T20:37:46Z"}},{"time":"2011-07-19T20:37:46Z","comment":{"is_private":false,"creator":{"real_name":"Ehsan Akhgari [:ehsan]","name":"ehsan"},"text":"","id":5599990,"creation_time":"2011-07-19T20:37:46Z"}},{"time":"2011-07-19T17:37:11Z","changeset":{"changes":[{"removed":"","added":"fayearthur+bugs@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-07-19T17:37:11Z"}},{"time":"2011-07-19T17:35:58Z","changeset":{"changes":[{"removed":"","added":"ctalbert@mozilla.com, jhammel@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-07-19T17:35:58Z"}},{"time":"2011-07-18T12:00:25Z","changeset":{"changes":[{"removed":"","added":"ted.mielczarek@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ted.mielczarek@gmail.com","name":"ted.mielczarek@gmail.com"},"change_time":"2011-07-18T12:00:25Z"}}]},{"bug":{"history":[{"changes":[{"attachment_id":"546836","removed":"text/x-python","added":"text/plain","field_name":"attachment.content_type"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-19T18:28:25Z"},{"changes":[{"removed":"","added":"ctalbert@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-07-19T17:58:20Z"}],"summary":"mozprofile should set permissions for profiles","last_change_time":"2011-07-19T18:28:25Z","comments":[{"is_private":false,"creator":{"real_name":"Joel Maher (:jmaher)","name":"jmaher"},"text":"","id":5599602,"creation_time":"2011-07-19T18:15:26Z"},{"is_private":false,"creator":{"real_name":"Joel Maher (:jmaher)","name":"jmaher"},"text":"","id":5599285,"creation_time":"2011-07-19T16:21:34Z"},{"is_private":false,"creator":{"real_name":"Joel Maher (:jmaher)","name":"jmaher"},"text":"","id":5554367,"creation_time":"2011-06-24T17:41:38Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5552758,"creation_time":"2011-06-23T23:26:21Z"}],"id":666791},"events":[{"time":"2011-07-19T18:28:25Z","changeset":{"changes":[{"attachment_id":"546836","removed":"text/x-python","added":"text/plain","field_name":"attachment.content_type"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-19T18:28:25Z"}},{"time":"2011-07-19T18:15:26Z","comment":{"is_private":false,"creator":{"real_name":"Joel Maher (:jmaher)","name":"jmaher"},"text":"","id":5599602,"creation_time":"2011-07-19T18:15:26Z"}},{"time":"2011-07-19T17:58:20Z","changeset":{"changes":[{"removed":"","added":"ctalbert@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-07-19T17:58:20Z"}},{"time":"2011-07-19T16:21:34Z","comment":{"is_private":false,"creator":{"real_name":"Joel Maher (:jmaher)","name":"jmaher"},"text":"","id":5599285,"creation_time":"2011-07-19T16:21:34Z"}}]},{"bug":{"history":[{"changes":[{"removed":"NEW","added":"RESOLVED","field_name":"status"},{"removed":"","added":"FIXED","field_name":"resolution"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-19T17:57:44Z"},{"changes":[{"removed":"nobody@mozilla.org","added":"jhammel@mozilla.com","field_name":"assigned_to"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-19T15:39:01Z"},{"changes":[{"removed":"[mozmill-2.0?]","added":"[mozmill-2.0+]","field_name":"whiteboard"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-19T04:24:09Z"},{"changes":[{"attachment_id":"545960","removed":"review?(ctalbert@mozilla.com)","added":"review+","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-07-18T22:04:12Z"},{"changes":[{"attachment_id":"545960","removed":"","added":"review?(ctalbert@mozilla.com)","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-14T18:16:53Z"},{"changes":[{"removed":"","added":"ctalbert@mozilla.com, fayearthur+bugs@gmail.com","field_name":"cc"},{"removed":"","added":"[mozmill-2.0?]","field_name":"whiteboard"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-13T21:37:01Z"}],"summary":"mutt processhandler and mozprocess processhandler: to merge?","last_change_time":"2011-07-19T17:57:44Z","comments":[{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5599538,"creation_time":"2011-07-19T17:57:44Z"},{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":5597782,"creation_time":"2011-07-18T22:04:12Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5591772,"creation_time":"2011-07-14T18:16:53Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5590023,"creation_time":"2011-07-13T21:35:42Z"}],"id":671420},"events":[{"time":"2011-07-19T17:57:44Z","changeset":{"changes":[{"removed":"NEW","added":"RESOLVED","field_name":"status"},{"removed":"","added":"FIXED","field_name":"resolution"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-19T17:57:44Z"}},{"time":"2011-07-19T17:57:44Z","comment":{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5599538,"creation_time":"2011-07-19T17:57:44Z"}},{"time":"2011-07-19T15:39:01Z","changeset":{"changes":[{"removed":"nobody@mozilla.org","added":"jhammel@mozilla.com","field_name":"assigned_to"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-19T15:39:01Z"}},{"time":"2011-07-19T04:24:09Z","changeset":{"changes":[{"removed":"[mozmill-2.0?]","added":"[mozmill-2.0+]","field_name":"whiteboard"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-07-19T04:24:09Z"}},{"time":"2011-07-18T22:04:12Z","changeset":{"changes":[{"attachment_id":"545960","removed":"review?(ctalbert@mozilla.com)","added":"review+","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-07-18T22:04:12Z"}},{"time":"2011-07-18T22:04:12Z","comment":{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":5597782,"creation_time":"2011-07-18T22:04:12Z"}}]},{"bug":{"history":[{"changes":[{"attachment_id":"546171","removed":"review?(fayearthur+bugs@gmail.com)","added":"review+","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/fayearthur+bugs@gmail.com","name":"fayearthur+bugs@gmail.com"},"change_time":"2011-07-19T17:42:04Z"},{"changes":[{"attachment_id":"546171","removed":"","added":"review?(fayearthur+bugs@gmail.com), feedback?(halbersa@gmail.com)","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-07-15T16:21:21Z"},{"changes":[{"attachment_id":"545775","removed":"review?(fayearthur+bugs@gmail.com)","added":"review+","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/fayearthur+bugs@gmail.com","name":"fayearthur+bugs@gmail.com"},"change_time":"2011-07-14T19:40:03Z"},{"changes":[{"attachment_id":"545771","removed":"0","added":"1","field_name":"attachment.is_obsolete"},{"attachment_id":"545771","removed":"review?(fayearthur+bugs@gmail.com)","added":"","field_name":"flag"},{"attachment_id":"545775","removed":"","added":"review?(fayearthur+bugs@gmail.com)","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-07-13T23:19:12Z"},{"changes":[{"attachment_id":"545771","removed":"","added":"review?(fayearthur+bugs@gmail.com)","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-07-13T23:14:09Z"},{"changes":[{"attachment_id":"535258","removed":"0","added":"1","field_name":"attachment.is_obsolete"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-07-13T23:12:37Z"},{"changes":[{"removed":"","added":"661408","field_name":"blocks"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-06-28T23:56:05Z"},{"changes":[{"attachment_id":"535258","removed":"feedback?(hskupin@gmail.com)","added":"feedback-","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-05-26T07:48:02Z"},{"changes":[{"attachment_id":"535258","removed":"","added":"feedback?(hskupin@gmail.com)","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-05-26T02:57:15Z"},{"changes":[{"removed":"","added":"halbersa@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-05-26T02:48:33Z"},{"changes":[{"removed":"waitForPageLoad() fails if the document owner is not a tab but an HTMLDocument","added":"waitForPageLoad() fails if the document owner is not a tab but an HTMLDocument (add support for iframes)","field_name":"summary"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-05-25T23:56:38Z"},{"changes":[{"attachment_id":"534720","removed":"review?(ctalbert@mozilla.com)","added":"review+","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-05-25T23:50:33Z"},{"changes":[{"removed":"","added":"fayearthur+bugs@gmail.com","field_name":"cc"},{"removed":"[mozmill-1.5.4+]","added":"[mozmill-1.5.4+][mozmill-2.0+]","field_name":"whiteboard"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-05-25T12:08:34Z"},{"changes":[{"removed":"","added":"ctalbert@mozilla.com","field_name":"cc"},{"removed":"[mozmill-1.5.4?]","added":"[mozmill-1.5.4+]","field_name":"whiteboard"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-05-24T21:25:21Z"},{"changes":[{"attachment_id":"534714","removed":"0","added":"1","field_name":"attachment.is_obsolete"},{"attachment_id":"534714","removed":"review?(ctalbert@mozilla.com)","added":"","field_name":"flag"},{"attachment_id":"534720","removed":"","added":"review?(ctalbert@mozilla.com)","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-05-24T11:15:13Z"},{"changes":[{"attachment_id":"534445","removed":"0","added":"1","field_name":"attachment.is_obsolete"},{"attachment_id":"534714","removed":"","added":"review?(ctalbert@mozilla.com)","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-05-24T10:59:06Z"},{"changes":[{"removed":"waitForPageLoad() fails for Discovery Pane with 'Specified tab hasn't been found.'","added":"waitForPageLoad() fails if the document owner is not a tab but an HTMLDocument","field_name":"summary"},{"removed":"","added":"in-testsuite?","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-05-24T10:53:16Z"},{"changes":[{"removed":"waitForPageLoad() fails for iFrames with 'Specified tab hasn't been found.'","added":"waitForPageLoad() fails for Discovery Pane with 'Specified tab hasn't been found.'","field_name":"summary"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-05-24T00:22:33Z"},{"changes":[{"removed":"","added":"[mozmill-1.5.4?]","field_name":"whiteboard"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-05-23T21:33:23Z"},{"changes":[{"removed":"","added":"regression","field_name":"keywords"},{"removed":"NEW","added":"ASSIGNED","field_name":"status"},{"removed":"x86_64","added":"All","field_name":"platform"},{"removed":"","added":"604878","field_name":"blocks"},{"removed":"nobody@mozilla.org","added":"hskupin@gmail.com","field_name":"assigned_to"},{"removed":"waitForPageLoad() does not handle iframes","added":"waitForPageLoad() fails for iFrames with 'Specified tab hasn't been found.'","field_name":"summary"},{"removed":"Linux","added":"All","field_name":"op_sys"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-05-23T15:59:53Z"},{"changes":[{"removed":"","added":"alex.lakatos@softvision.ro, hskupin@gmail.com, vlad.maniac@softvision.ro","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/vlad.maniac@softvision.ro","name":"vlad.maniac@softvision.ro"},"change_time":"2011-05-23T15:24:49Z"}],"summary":"waitForPageLoad() fails if the document owner is not a tab but an HTMLDocument (add support for iframes)","last_change_time":"2011-07-19T17:42:04Z","comments":[{"is_private":false,"creator":{"real_name":"Heather Arthur [:harth]","name":"fayearthur+bugs"},"text":"","id":5599498,"creation_time":"2011-07-19T17:42:04Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5593624,"creation_time":"2011-07-15T16:21:21Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5592472,"creation_time":"2011-07-14T22:38:58Z"},{"is_private":false,"creator":{"real_name":"Heather Arthur [:harth]","name":"fayearthur+bugs"},"text":"","id":5591961,"creation_time":"2011-07-14T19:40:03Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5590242,"creation_time":"2011-07-13T23:19:12Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5590234,"creation_time":"2011-07-13T23:14:09Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5590231,"creation_time":"2011-07-13T23:12:37Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5494401,"creation_time":"2011-05-26T07:48:02Z"},{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":5494130,"creation_time":"2011-05-26T02:58:56Z"},{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":5494127,"creation_time":"2011-05-26T02:57:15Z"},{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":5493838,"creation_time":"2011-05-25T23:50:33Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5491980,"creation_time":"2011-05-25T12:08:34Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5488829,"creation_time":"2011-05-24T11:18:12Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5488828,"creation_time":"2011-05-24T11:15:13Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5488811,"creation_time":"2011-05-24T10:59:06Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5488807,"creation_time":"2011-05-24T10:53:16Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5488698,"creation_time":"2011-05-24T09:37:36Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5488122,"creation_time":"2011-05-24T00:22:33Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5487989,"creation_time":"2011-05-23T23:17:41Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5487883,"creation_time":"2011-05-23T22:39:31Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5487655,"creation_time":"2011-05-23T21:33:23Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5486617,"creation_time":"2011-05-23T15:59:53Z"},{"is_private":false,"creator":{"real_name":"Maniac Vlad Florin (:vladmaniac)","name":"vlad.maniac"},"text":"","id":5486535,"creation_time":"2011-05-23T15:23:48Z"}],"id":659000},"events":[{"time":"2011-07-19T17:42:04Z","changeset":{"changes":[{"attachment_id":"546171","removed":"review?(fayearthur+bugs@gmail.com)","added":"review+","field_name":"flag"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/fayearthur+bugs@gmail.com","name":"fayearthur+bugs@gmail.com"},"change_time":"2011-07-19T17:42:04Z"}},{"time":"2011-07-19T17:42:04Z","comment":{"is_private":false,"creator":{"real_name":"Heather Arthur [:harth]","name":"fayearthur+bugs"},"text":"","id":5599498,"creation_time":"2011-07-19T17:42:04Z"}}]},{"bug":{"history":[],"summary":"QA Companion marked incompatible for Firefox versions higher than 6.*.","last_change_time":"2011-07-18T23:00:06Z","comments":[{"is_private":false,"creator":{"real_name":"Al Billings [:abillings]","name":"abillings"},"text":"","id":5597976,"creation_time":"2011-07-18T23:00:06Z"}],"id":672393},"events":[{"time":"2011-07-18T23:00:06Z","comment":{"is_private":false,"creator":{"real_name":"Al Billings [:abillings]","name":"abillings"},"text":"","id":5597976,"creation_time":"2011-07-18T23:00:06Z"}}]},{"bug":{"history":[{"changes":[{"removed":"","added":"khuey@kylehuey.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/khuey@kylehuey.com","name":"khuey@kylehuey.com"},"change_time":"2011-07-18T20:35:37Z"},{"changes":[{"removed":"","added":"kairo@kairo.at","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/kairo@kairo.at","name":"kairo@kairo.at"},"change_time":"2010-04-05T16:18:55Z"},{"changes":[{"removed":"","added":"mook.moz+mozbz@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mook@songbirdnest.com","name":"mook@songbirdnest.com"},"change_time":"2010-03-16T21:34:23Z"},{"changes":[{"removed":"","added":"harthur@cmu.edu","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/fayearthur+bugs@gmail.com","name":"fayearthur+bugs@gmail.com"},"change_time":"2010-03-16T04:31:00Z"},{"changes":[{"removed":"","added":"ted.mielczarek@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ted.mielczarek@gmail.com","name":"ted.mielczarek@gmail.com"},"change_time":"2010-03-15T23:52:39Z"},{"changes":[{"removed":"","added":"552533","field_name":"depends_on"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/dwitte@gmail.com","name":"dwitte@gmail.com"},"change_time":"2010-03-15T22:02:20Z"},{"changes":[{"removed":"","added":"447581","field_name":"blocks"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/dietrich@mozilla.com","name":"dietrich@mozilla.com"},"change_time":"2010-03-02T23:57:25Z"},{"changes":[{"removed":"412531","added":"","field_name":"blocks"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/dietrich@mozilla.com","name":"dietrich@mozilla.com"},"change_time":"2009-12-11T02:49:08Z"},{"changes":[{"removed":"","added":"Pidgeot18@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/Pidgeot18@gmail.com","name":"Pidgeot18@gmail.com"},"change_time":"2009-10-26T14:47:22Z"},{"changes":[{"removed":"js-ctypes","added":"js-ctypes","field_name":"component"},{"removed":"Trunk","added":"unspecified","field_name":"version"},{"removed":"Other Applications","added":"Core","field_name":"product"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mozillamarcia.knous@gmail.com","name":"mozillamarcia.knous@gmail.com"},"change_time":"2009-10-02T10:17:18Z"},{"changes":[{"removed":"","added":"jwalden+bmo@mit.edu","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jwalden+bmo@mit.edu","name":"jwalden+bmo@mit.edu"},"change_time":"2009-08-17T19:11:28Z"},{"changes":[{"removed":"","added":"ajvincent@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ajvincent@gmail.com","name":"ajvincent@gmail.com"},"change_time":"2009-08-13T00:28:01Z"},{"changes":[{"removed":"","added":"benjamin@smedbergs.us","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/benjamin@smedbergs.us","name":"benjamin@smedbergs.us"},"change_time":"2009-07-23T03:14:04Z"},{"changes":[{"removed":"","added":"highmind63@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/highmind63@gmail.com","name":"highmind63@gmail.com"},"change_time":"2009-07-23T01:02:51Z"},{"changes":[{"removed":"","added":"shaver@mozilla.org","field_name":"cc"},{"removed":"JavaScript Engine","added":"js-ctypes","field_name":"component"},{"removed":"general@js.bugs","added":"nobody@mozilla.org","field_name":"assigned_to"},{"removed":"Core","added":"Other Applications","field_name":"product"},{"removed":"add a pinvoke-like method to js","added":"Support C++ calling from JSctypes","field_name":"summary"},{"removed":"general@spidermonkey.bugs","added":"js-ctypes@otherapps.bugs","field_name":"qa_contact"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/shaver@mozilla.org","name":"shaver@mozilla.org"},"change_time":"2009-07-23T00:55:48Z"},{"changes":[{"removed":"","added":"ryanvm@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ryanvm@gmail.com","name":"ryanvm@gmail.com"},"change_time":"2009-07-23T00:34:18Z"},{"changes":[{"removed":"","added":"412531","field_name":"blocks"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/dietrich@mozilla.com","name":"dietrich@mozilla.com"},"change_time":"2009-07-23T00:06:41Z"},{"changes":[{"removed":"","added":"dvander@alliedmods.net","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/dvander@alliedmods.net","name":"dvander@alliedmods.net"},"change_time":"2009-07-23T00:03:46Z"},{"changes":[{"removed":"","added":"dietrich@mozilla.com, mark.finkle@gmail.com","field_name":"cc"},{"removed":"","added":"[ts][tsnap]","field_name":"whiteboard"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/dietrich@mozilla.com","name":"dietrich@mozilla.com"},"change_time":"2009-07-22T23:58:23Z"}],"summary":"Support C++ calling from JSctypes","last_change_time":"2011-07-18T20:35:37Z","comments":[{"is_private":false,"creator":{"real_name":"Ted Mielczarek [:ted, :luser]","name":"ted.mielczarek"},"text":"","id":4586274,"creation_time":"2010-03-15T23:52:39Z"},{"is_private":false,"creator":{"real_name":"Dan Witte (:dwitte)","name":"dwitte"},"text":"","id":4586028,"creation_time":"2010-03-15T22:21:21Z"},{"is_private":false,"creator":{"real_name":"Dan Witte (:dwitte)","name":"dwitte"},"text":"","id":4586006,"creation_time":"2010-03-15T22:11:11Z"},{"is_private":false,"creator":{"real_name":"Joshua Cranmer [:jcranmer]","name":"Pidgeot18"},"text":"","id":4364260,"creation_time":"2009-10-26T18:33:21Z"},{"is_private":false,"creator":{"real_name":"Dan Witte (:dwitte)","name":"dwitte"},"text":"","id":4364119,"creation_time":"2009-10-26T17:27:05Z"},{"is_private":false,"creator":{"real_name":"Joshua Cranmer [:jcranmer]","name":"Pidgeot18"},"text":"","id":4363794,"creation_time":"2009-10-26T14:47:22Z"},{"is_private":false,"creator":{"real_name":"Benjamin Smedberg [:bsmedberg]","name":"benjamin"},"text":"","id":4211892,"creation_time":"2009-07-23T03:14:04Z"},{"is_private":false,"creator":{"real_name":"Mike Shaver (:shaver)","name":"shaver"},"text":"","id":4211710,"creation_time":"2009-07-23T00:56:10Z"},{"is_private":false,"creator":{"real_name":"Taras Glek (:taras)","name":"tglek"},"text":"","id":4211707,"creation_time":"2009-07-23T00:54:06Z"},{"is_private":false,"creator":{"real_name":"Mike Shaver (:shaver)","name":"shaver"},"text":"","id":4211677,"creation_time":"2009-07-23T00:42:01Z"},{"is_private":false,"creator":{"real_name":"Taras Glek (:taras)","name":"tglek"},"text":"","id":4211672,"creation_time":"2009-07-23T00:40:10Z"},{"is_private":false,"creator":{"real_name":"Mike Shaver (:shaver)","name":"shaver"},"text":"","id":4211668,"creation_time":"2009-07-23T00:38:34Z"},{"is_private":false,"creator":{"real_name":"Taras Glek (:taras)","name":"tglek"},"text":"","id":4211665,"creation_time":"2009-07-23T00:36:58Z"},{"is_private":false,"creator":{"real_name":"Mike Shaver (:shaver)","name":"shaver"},"text":"","id":4211660,"creation_time":"2009-07-23T00:34:27Z"},{"is_private":false,"creator":{"real_name":"Taras Glek (:taras)","name":"tglek"},"text":"","id":4211624,"creation_time":"2009-07-23T00:15:38Z"},{"is_private":false,"creator":{"real_name":"Mike Shaver (:shaver)","name":"shaver"},"text":"","id":4211608,"creation_time":"2009-07-23T00:08:16Z"},{"is_private":false,"creator":{"real_name":"Taras Glek (:taras)","name":"tglek"},"text":"","id":4211586,"creation_time":"2009-07-22T23:57:14Z"}],"id":505907},"events":[{"time":"2011-07-18T20:35:37Z","changeset":{"changes":[{"removed":"","added":"khuey@kylehuey.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/khuey@kylehuey.com","name":"khuey@kylehuey.com"},"change_time":"2011-07-18T20:35:37Z"}}]},{"bug":{"history":[{"changes":[{"removed":"","added":"bmo@edmorley.co.uk","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/bmo@edmorley.co.uk","name":"bmo@edmorley.co.uk"},"change_time":"2011-07-10T14:30:39Z"},{"changes":[{"removed":"","added":"bear@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/bear@mozilla.com","name":"bear@mozilla.com"},"change_time":"2011-07-07T21:21:56Z"},{"changes":[{"removed":"","added":"ctalbert@mozilla.com, fayearthur+bugs@gmail.com, sliu@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-07-07T21:19:46Z"},{"changes":[{"removed":"","added":"armenzg@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/armenzg@mozilla.com","name":"armenzg@mozilla.com"},"change_time":"2011-07-07T17:04:41Z"}],"summary":"Publish Build Faster metrics","last_change_time":"2011-07-18T20:25:40Z","comments":[{"is_private":false,"creator":{"real_name":"Chris AtLee [:catlee]","name":"catlee"},"text":"","id":5597430,"creation_time":"2011-07-18T20:25:40Z"},{"is_private":false,"creator":{"real_name":"Sam Liu","name":"sliu"},"text":"","id":5597428,"creation_time":"2011-07-18T20:24:35Z"},{"is_private":false,"creator":{"real_name":"Chris AtLee [:catlee]","name":"catlee"},"text":"","id":5597393,"creation_time":"2011-07-18T20:10:45Z"},{"is_private":false,"creator":{"real_name":"Sam Liu","name":"sliu"},"text":"","id":5589839,"creation_time":"2011-07-13T20:20:49Z"},{"is_private":false,"creator":{"real_name":"Chris AtLee [:catlee]","name":"catlee"},"text":"","id":5582189,"creation_time":"2011-07-09T01:25:21Z"},{"is_private":false,"creator":{"real_name":"Sam Liu","name":"sliu"},"text":"","id":5581446,"creation_time":"2011-07-08T18:25:33Z"},{"is_private":false,"creator":{"real_name":"Armen Zambrano G. [:armenzg] - Release Engineer","name":"armenzg"},"text":"","id":5580728,"creation_time":"2011-07-08T12:36:01Z"},{"is_private":false,"creator":{"real_name":"Chris AtLee [:catlee]","name":"catlee"},"text":"","id":5580206,"creation_time":"2011-07-08T03:21:41Z"},{"is_private":false,"creator":{"real_name":"Sam Liu","name":"sliu"},"text":"","id":5579985,"creation_time":"2011-07-08T00:01:37Z"},{"is_private":false,"creator":{"real_name":"Chris AtLee [:catlee]","name":"catlee"},"text":"","id":5579980,"creation_time":"2011-07-07T23:57:48Z"},{"is_private":false,"creator":{"real_name":"Sam Liu","name":"sliu"},"text":"","id":5579965,"creation_time":"2011-07-07T23:51:02Z"},{"is_private":false,"creator":{"real_name":"Chris AtLee [:catlee]","name":"catlee"},"text":"","id":5579631,"creation_time":"2011-07-07T21:32:17Z"},{"is_private":false,"creator":{"real_name":"Mike Taylor [:bear]","name":"bear"},"text":"","id":5579612,"creation_time":"2011-07-07T21:21:56Z"},{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":5579605,"creation_time":"2011-07-07T21:19:46Z"},{"is_private":false,"creator":{"real_name":"Chris AtLee [:catlee]","name":"catlee"},"text":"","id":5578932,"creation_time":"2011-07-07T17:02:45Z"}],"id":669930},"events":[{"time":"2011-07-18T20:25:40Z","comment":{"is_private":false,"creator":{"real_name":"Chris AtLee [:catlee]","name":"catlee"},"text":"","id":5597430,"creation_time":"2011-07-18T20:25:40Z"}},{"time":"2011-07-18T20:24:35Z","comment":{"is_private":false,"creator":{"real_name":"Sam Liu","name":"sliu"},"text":"","id":5597428,"creation_time":"2011-07-18T20:24:35Z"}},{"time":"2011-07-18T20:10:45Z","comment":{"is_private":false,"creator":{"real_name":"Chris AtLee [:catlee]","name":"catlee"},"text":"","id":5597393,"creation_time":"2011-07-18T20:10:45Z"}}]},{"bug":{"history":[{"changes":[{"removed":"","added":"jwatt@jwatt.org","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jwatt@jwatt.org","name":"jwatt@jwatt.org"},"change_time":"2011-07-18T12:06:33Z"},{"changes":[{"removed":"","added":"taku.eof@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/taku.eof@gmail.com","name":"taku.eof@gmail.com"},"change_time":"2011-06-27T04:50:23Z"},{"changes":[{"removed":"","added":"jeff@stikman.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jeff@stikman.com","name":"jeff@stikman.com"},"change_time":"2011-05-30T15:15:06Z"},{"changes":[{"removed":"","added":"spencerselander@yahoo.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/spencerselander@yahoo.com","name":"spencerselander@yahoo.com"},"change_time":"2011-05-18T07:58:37Z"},{"changes":[{"removed":"VanillaMozilla@hotmail.com","added":"","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/VanillaMozilla@hotmail.com","name":"VanillaMozilla@hotmail.com"},"change_time":"2011-05-17T02:57:17Z"},{"changes":[{"removed":"","added":"mcdavis941.bugs@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mcdavis941.bugs@gmail.com","name":"mcdavis941.bugs@gmail.com"},"change_time":"2011-05-16T21:08:18Z"},{"changes":[{"removed":"beltzner@mozilla.com","added":"","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mbeltzner@gmail.com","name":"mbeltzner@gmail.com"},"change_time":"2011-04-02T00:17:26Z"},{"changes":[{"removed":"","added":"cbaker@customsoftwareconsult.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/cbaker@customsoftwareconsult.com","name":"cbaker@customsoftwareconsult.com"},"change_time":"2011-03-28T14:08:35Z"},{"changes":[{"removed":"","added":"SGrage@gmx.net","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/SGrage@gmx.net","name":"SGrage@gmx.net"},"change_time":"2011-03-28T10:13:51Z"},{"changes":[{"removed":"","added":"dewmigg@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/dewmigg@gmail.com","name":"dewmigg@gmail.com"},"change_time":"2011-03-13T21:34:21Z"},{"changes":[{"removed":"","added":"ulysse@email.it","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/euryalus.0@gmail.com","name":"euryalus.0@gmail.com"},"change_time":"2011-03-13T12:14:04Z"},{"changes":[{"removed":"","added":"heraldo99@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/heraldo99@gmail.com","name":"heraldo99@gmail.com"},"change_time":"2011-03-13T11:36:08Z"},{"changes":[{"removed":"","added":"pardal@gmx.de","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/pardal@gmx.de","name":"pardal@gmx.de"},"change_time":"2011-03-13T02:48:03Z"},{"changes":[{"removed":"","added":"terrell.kelley@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/terrell.kelley@gmail.com","name":"terrell.kelley@gmail.com"},"change_time":"2011-01-31T11:46:28Z"},{"changes":[{"removed":"","added":"kiuzeppe@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/kiuzeppe@gmail.com","name":"kiuzeppe@gmail.com"},"change_time":"2011-01-20T22:13:01Z"},{"changes":[{"removed":"","added":"saneyuki.snyk@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/saneyuki.s.snyk@gmail.com","name":"saneyuki.s.snyk@gmail.com"},"change_time":"2011-01-11T09:25:01Z"},{"changes":[{"removed":"","added":"stephen.donner@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/stephen.donner@gmail.com","name":"stephen.donner@gmail.com"},"change_time":"2011-01-04T21:07:17Z"},{"changes":[{"removed":"","added":"prog_when_resolved_notification@bluebottle.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/prog_when_resolved_notification@bluebottle.com","name":"prog_when_resolved_notification@bluebottle.com"},"change_time":"2011-01-02T18:11:00Z"},{"changes":[{"removed":"jmjeffery@embarqmail.com","added":"","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jmjeffery@embarqmail.com","name":"jmjeffery@embarqmail.com"},"change_time":"2010-12-14T18:17:14Z"},{"changes":[{"removed":"","added":"colmeiro@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/colmeiro@gmail.com","name":"colmeiro@gmail.com"},"change_time":"2010-12-10T23:46:15Z"},{"changes":[{"removed":"","added":"willyaranda@mozilla-hispano.org","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/willyaranda@mozilla-hispano.org","name":"willyaranda@mozilla-hispano.org"},"change_time":"2010-12-10T22:34:30Z"},{"changes":[{"removed":"","added":"dale.bugzilla@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/dale.bugzilla@gmail.com","name":"dale.bugzilla@gmail.com"},"change_time":"2010-12-10T00:50:10Z"},{"changes":[{"removed":"","added":"sabret00the@yahoo.co.uk","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/sabret00the@yahoo.co.uk","name":"sabret00the@yahoo.co.uk"},"change_time":"2010-12-09T17:01:15Z"},{"changes":[{"removed":"","added":"daveryeo@telus.net","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/daveryeo@telus.net","name":"daveryeo@telus.net"},"change_time":"2010-12-09T04:46:59Z"},{"changes":[{"removed":"","added":"bugspam.Callek@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/bugspam.Callek@gmail.com","name":"bugspam.Callek@gmail.com"},"change_time":"2010-12-09T01:05:37Z"},{"changes":[{"removed":"","added":"mcepl@redhat.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mcepl@redhat.com","name":"mcepl@redhat.com"},"change_time":"2010-12-08T23:55:49Z"},{"changes":[{"removed":"","added":"tymerkaev@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/tymerkaev@gmail.com","name":"tymerkaev@gmail.com"},"change_time":"2010-11-29T10:19:49Z"},{"changes":[{"removed":"","added":"kwierso@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/kwierso@gmail.com","name":"kwierso@gmail.com"},"change_time":"2010-11-29T05:42:05Z"},{"changes":[{"removed":"","added":"mtanalin@yandex.ru","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mtanalin@yandex.ru","name":"mtanalin@yandex.ru"},"change_time":"2010-11-15T22:33:18Z"},{"changes":[{"removed":"","added":"briks.si@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/briks.si@gmail.com","name":"briks.si@gmail.com"},"change_time":"2010-11-15T20:45:37Z"},{"changes":[{"removed":"","added":"mozdiav@aeons.lv","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mozdiav@aeons.lv","name":"mozdiav@aeons.lv"},"change_time":"2010-11-12T20:25:54Z"},{"changes":[{"removed":"","added":"soufian.j@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/soufian.j@gmail.com","name":"soufian.j@gmail.com"},"change_time":"2010-11-12T16:43:16Z"},{"changes":[{"removed":"","added":"jmjeffery@embarqmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jmjeffery@embarqmail.com","name":"jmjeffery@embarqmail.com"},"change_time":"2010-11-12T12:59:58Z"},{"changes":[{"removed":"","added":"markc@qsiuk.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/markc@qsiuk.com","name":"markc@qsiuk.com"},"change_time":"2010-11-12T12:14:42Z"},{"changes":[{"removed":"","added":"thibaut.bethune@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/thibaut.bethune@gmail.com","name":"thibaut.bethune@gmail.com"},"change_time":"2010-11-11T22:54:55Z"},{"changes":[{"removed":"","added":"gmontagu@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/gmontagu@gmail.com","name":"gmontagu@gmail.com"},"change_time":"2010-11-11T22:45:52Z"},{"changes":[{"removed":"","added":"KenSaunders@AccessFirefox.org","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/KenSaunders@AccessFirefox.org","name":"KenSaunders@AccessFirefox.org"},"change_time":"2010-11-11T19:26:57Z"},{"changes":[{"removed":"","added":"lists@eitanadler.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/lists@eitanadler.com","name":"lists@eitanadler.com"},"change_time":"2010-11-11T18:07:05Z"},{"changes":[{"removed":"","added":"geekshadow@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/geekshadow@gmail.com","name":"geekshadow@gmail.com"},"change_time":"2010-10-20T09:22:55Z"},{"changes":[{"removed":"","added":"webmaster@keryx.se","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/webmaster@keryx.se","name":"webmaster@keryx.se"},"change_time":"2010-10-20T09:06:57Z"},{"changes":[{"removed":"","added":"bugzilla@zirro.se","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/bugzilla@zirro.se","name":"bugzilla@zirro.se"},"change_time":"2010-10-20T09:03:47Z"},{"changes":[{"removed":"","added":"supernova00@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/supernova00@gmail.com","name":"supernova00@gmail.com"},"change_time":"2010-10-19T21:35:02Z"},{"changes":[{"removed":"","added":"beltzner@mozilla.com, dtownsend@mozilla.com, jgriffin@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jgriffin@mozilla.com","name":"jgriffin@mozilla.com"},"change_time":"2010-10-08T22:07:52Z"},{"changes":[{"removed":"","added":"gavin.sharp@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/gavin.sharp@gmail.com","name":"gavin.sharp@gmail.com"},"change_time":"2010-09-24T18:44:50Z"},{"changes":[{"removed":"","added":"omarb.public@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/omarb.public@gmail.com","name":"omarb.public@gmail.com"},"change_time":"2010-09-06T18:12:39Z"},{"changes":[{"removed":"","added":"David.Vo2+bmo@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/auscompgeek@sumovolunteers.org","name":"auscompgeek@sumovolunteers.org"},"change_time":"2010-09-03T02:57:43Z"},{"changes":[{"removed":"","added":"mcs@pearlcrescent.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mcs@pearlcrescent.com","name":"mcs@pearlcrescent.com"},"change_time":"2010-09-02T02:33:22Z"},{"changes":[{"removed":"","added":"archaeopteryx@coole-files.de","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/archaeopteryx@coole-files.de","name":"archaeopteryx@coole-files.de"},"change_time":"2010-09-01T09:17:01Z"},{"changes":[{"removed":"","added":"antoine.mechelynck@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/antoine.mechelynck@gmail.com","name":"antoine.mechelynck@gmail.com"},"change_time":"2010-09-01T03:05:29Z"},{"changes":[{"removed":"","added":"m-wada@japan.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/m-wada@japan.com","name":"m-wada@japan.com"},"change_time":"2010-08-31T09:53:39Z"},{"changes":[{"removed":"","added":"bugzilla@standard8.plus.com, ludovic@mozillamessaging.com, vseerror@lehigh.edu","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ludovic@mozilla.com","name":"ludovic@mozilla.com"},"change_time":"2010-08-31T06:10:50Z"},{"changes":[{"removed":"","added":"grenavitar@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/grenavitar@gmail.com","name":"grenavitar@gmail.com"},"change_time":"2010-08-31T03:59:31Z"},{"changes":[{"removed":"","added":"jorge@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jorge@mozilla.com","name":"jorge@mozilla.com"},"change_time":"2010-08-30T18:18:56Z"},{"changes":[{"removed":"","added":"ehsan@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ehsan@mozilla.com","name":"ehsan@mozilla.com"},"change_time":"2010-08-30T18:09:28Z"},{"changes":[{"removed":"","added":"tyler.downer@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/tyler.downer@gmail.com","name":"tyler.downer@gmail.com"},"change_time":"2010-08-30T17:40:02Z"},{"changes":[{"removed":"","added":"asqueella@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/asqueella@gmail.com","name":"asqueella@gmail.com"},"change_time":"2010-08-26T20:47:46Z"},{"changes":[{"removed":"","added":"590788","field_name":"depends_on"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2010-08-26T15:49:52Z"},{"changes":[{"removed":"","added":"benjamin@smedbergs.us","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2010-08-26T08:24:38Z"},{"changes":[{"removed":"","added":"bugs-bmo@unknownbrackets.org","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/bugs-bmo@unknownbrackets.org","name":"bugs-bmo@unknownbrackets.org"},"change_time":"2010-08-26T07:24:55Z"},{"changes":[{"removed":"","added":"highmind63@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/highmind63@gmail.com","name":"highmind63@gmail.com"},"change_time":"2010-08-26T03:45:34Z"},{"changes":[{"removed":"stream@abv.bg","added":"","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/stream@abv.bg","name":"stream@abv.bg"},"change_time":"2010-08-24T16:50:19Z"},{"changes":[{"removed":"Infrastructure","added":"ProfileManager","field_name":"component"},{"removed":"jhammel@mozilla.com","added":"nobody@mozilla.org","field_name":"assigned_to"},{"removed":"infra@testing.bugs","added":"profilemanager@testing.bugs","field_name":"qa_contact"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2010-08-24T15:27:00Z"},{"changes":[{"removed":"","added":"justin.lebar+bug@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/justin.lebar+bug@gmail.com","name":"justin.lebar+bug@gmail.com"},"change_time":"2010-07-28T21:26:38Z"},{"changes":[{"removed":"mozilla.bugs@alyoung.com","added":"","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mozilla.bugs@alyoung.com","name":"mozilla.bugs@alyoung.com"},"change_time":"2010-07-22T23:59:31Z"},{"changes":[{"removed":"","added":"deletesoftware@yandex.ru","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/deletesoftware@yandex.ru","name":"deletesoftware@yandex.ru"},"change_time":"2010-06-19T14:19:55Z"},{"changes":[{"removed":"NEW","added":"ASSIGNED","field_name":"status"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2010-06-14T17:26:17Z"},{"changes":[{"removed":"nobody@mozilla.org","added":"jhammel@mozilla.com","field_name":"assigned_to"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2010-05-27T15:42:33Z"},{"changes":[{"removed":"","added":"harthur@cmu.edu","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2010-03-18T20:49:42Z"},{"changes":[{"removed":"","added":"k0scist@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2010-03-09T17:10:48Z"},{"changes":[{"removed":"","added":"stream@abv.bg","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/stream@abv.bg","name":"stream@abv.bg"},"change_time":"2010-02-07T01:32:42Z"},{"changes":[{"removed":"","added":"VanillaMozilla@hotmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/VanillaMozilla@hotmail.com","name":"VanillaMozilla@hotmail.com"},"change_time":"2010-01-22T17:28:59Z"},{"changes":[{"removed":"","added":"reed@reedloden.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/reed@reedloden.com","name":"reed@reedloden.com"},"change_time":"2010-01-17T19:22:31Z"},{"changes":[{"removed":"","added":"blizzard@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/blizzard@mozilla.com","name":"blizzard@mozilla.com"},"change_time":"2010-01-17T01:12:28Z"},{"changes":[{"removed":"","added":"540194","field_name":"blocks"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/david@rossde.com","name":"david@rossde.com"},"change_time":"2010-01-16T19:18:12Z"},{"changes":[{"removed":"","added":"fullmetaljacket.xp+bugmail@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/fullmetaljacket.xp+bugmail@gmail.com","name":"fullmetaljacket.xp+bugmail@gmail.com"},"change_time":"2010-01-15T09:22:52Z"},{"changes":[{"removed":"","added":"wladow@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/wladow@gmail.com","name":"wladow@gmail.com"},"change_time":"2010-01-14T22:31:39Z"},{"changes":[{"removed":"278860","added":"","field_name":"depends_on"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2010-01-14T17:46:11Z"},{"changes":[{"removed":"","added":"chado_moz@yahoo.co.jp","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/chado_moz@yahoo.co.jp","name":"chado_moz@yahoo.co.jp"},"change_time":"2010-01-14T15:30:57Z"},{"changes":[{"removed":"","added":"mnyromyr@tprac.de","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mnyromyr@tprac.de","name":"mnyromyr@tprac.de"},"change_time":"2010-01-14T10:56:22Z"},{"changes":[{"removed":"","added":"spitfire.kuden@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/spitfire.kuden@gmail.com","name":"spitfire.kuden@gmail.com"},"change_time":"2010-01-14T10:15:48Z"},{"changes":[{"removed":"","added":"mozilla.bugs@alyoung.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mozilla.bugs@alyoung.com","name":"mozilla.bugs@alyoung.com"},"change_time":"2010-01-14T05:57:27Z"},{"changes":[{"removed":"","added":"nori@noasobi.net","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/nori@noasobi.net","name":"nori@noasobi.net"},"change_time":"2010-01-14T05:41:47Z"},{"changes":[{"removed":"","added":"michaelkohler@live.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/michaelkohler@linux.com","name":"michaelkohler@linux.com"},"change_time":"2010-01-14T01:39:36Z"},{"changes":[{"removed":"","added":"kairo@kairo.at","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/kairo@kairo.at","name":"kairo@kairo.at"},"change_time":"2010-01-14T00:16:58Z"},{"changes":[{"removed":"normal","added":"enhancement","field_name":"severity"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/david@rossde.com","name":"david@rossde.com"},"change_time":"2010-01-14T00:08:41Z"},{"changes":[{"removed":"","added":"ryanvm@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ryanvm@gmail.com","name":"ryanvm@gmail.com"},"change_time":"2010-01-14T00:02:33Z"},{"changes":[{"removed":"","added":"phiw@l-c-n.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/phiw@l-c-n.com","name":"phiw@l-c-n.com"},"change_time":"2010-01-13T23:56:59Z"},{"changes":[{"removed":"","added":"pcvrcek@mozilla.cz","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/pcvrcek@mozilla.cz","name":"pcvrcek@mozilla.cz"},"change_time":"2010-01-13T23:45:00Z"},{"changes":[{"removed":"","added":"axel@pike.org","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/l10n@mozilla.com","name":"l10n@mozilla.com"},"change_time":"2010-01-13T23:17:08Z"},{"changes":[{"removed":"","added":"stefanh@inbox.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/stefanh@inbox.com","name":"stefanh@inbox.com"},"change_time":"2010-01-13T23:12:13Z"},{"changes":[{"removed":"x86","added":"All","field_name":"platform"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2010-01-13T23:06:25Z"},{"changes":[{"removed":"","added":"johnath@mozilla.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/johnath@mozilla.com","name":"johnath@mozilla.com"},"change_time":"2010-01-13T23:04:10Z"},{"changes":[{"removed":"","added":"mrmazda@earthlink.net","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/mrmazda@earthlink.net","name":"mrmazda@earthlink.net"},"change_time":"2010-01-13T22:46:40Z"},{"changes":[{"removed":"","added":"iann_bugzilla@blueyonder.co.uk","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/iann_bugzilla@blueyonder.co.uk","name":"iann_bugzilla@blueyonder.co.uk"},"change_time":"2010-01-13T21:41:32Z"},{"changes":[{"removed":"","added":"xtc4uall@gmail.com","field_name":"cc"},{"removed":"","added":"214675","field_name":"blocks"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/xtc4uall@gmail.com","name":"xtc4uall@gmail.com"},"change_time":"2010-01-13T21:34:20Z"},{"changes":[{"removed":"","added":"hskupin@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2010-01-13T21:31:14Z"},{"changes":[{"removed":"","added":"hickendorffbas@gmail.com","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hickendorffbas@gmail.com","name":"hickendorffbas@gmail.com"},"change_time":"2010-01-13T20:58:31Z"}],"summary":"New Test/Triage Profile Manager Application","last_change_time":"2011-07-18T12:06:33Z","comments":[{"is_private":false,"creator":{"real_name":"Jonathan Griffin (:jgriffin)","name":"jgriffin"},"text":"","id":5480531,"creation_time":"2011-05-19T17:30:57Z"},{"is_private":false,"creator":{"real_name":"Spencer Selander [greenknight]","name":"spencerselander"},"text":"","id":5476603,"creation_time":"2011-05-18T07:58:37Z"},{"is_private":false,"creator":{"real_name":"Paul [sabret00the]","name":"sabret00the"},"text":"","id":5373656,"creation_time":"2011-03-28T06:59:22Z"},{"is_private":false,"creator":{"real_name":"Jonathan Griffin (:jgriffin)","name":"jgriffin"},"text":"","id":5240204,"creation_time":"2011-01-31T17:58:24Z"},{"is_private":false,"creator":{"real_name":"Terrell Kelley","name":"terrell.kelley"},"text":"","id":5239501,"creation_time":"2011-01-31T11:46:28Z"},{"is_private":false,"creator":{"real_name":"Benjamin Smedberg [:bsmedberg]","name":"benjamin"},"text":"","id":5002085,"creation_time":"2010-10-11T18:04:48Z"},{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":5002054,"creation_time":"2010-10-11T17:52:13Z"},{"is_private":false,"creator":{"real_name":"Dave Townsend (:Mossop)","name":"dtownsend"},"text":"","id":4999117,"creation_time":"2010-10-08T22:12:23Z"},{"is_private":false,"creator":{"real_name":"Jonathan Griffin (:jgriffin)","name":"jgriffin"},"text":"","id":4999107,"creation_time":"2010-10-08T22:07:52Z"},{"is_private":false,"creator":{"real_name":"Benjamin Smedberg [:bsmedberg]","name":"benjamin"},"text":"","id":4991281,"creation_time":"2010-10-06T18:42:20Z"},{"is_private":false,"creator":{"real_name":"David E. Ross","name":"david"},"text":"","id":4990011,"creation_time":"2010-10-06T17:50:51Z"},{"is_private":false,"creator":{"real_name":"Benjamin Smedberg [:bsmedberg]","name":"benjamin"},"text":"","id":4986111,"creation_time":"2010-10-05T02:54:24Z"},{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":4985884,"creation_time":"2010-10-05T00:30:08Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":4921920,"creation_time":"2010-09-08T15:20:06Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":4892626,"creation_time":"2010-08-26T16:05:50Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":4891863,"creation_time":"2010-08-26T08:24:38Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":4886114,"creation_time":"2010-08-24T15:31:05Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":4743315,"creation_time":"2010-06-14T17:26:17Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":4716160,"creation_time":"2010-05-27T16:53:53Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":4716148,"creation_time":"2010-05-27T16:44:32Z"},{"is_private":false,"creator":{"real_name":"David E. Ross","name":"david"},"text":"","id":4492322,"creation_time":"2010-01-18T15:12:52Z"},{"is_private":false,"creator":{"real_name":"Christopher Blizzard (:blizzard)","name":"blizzard"},"text":"","id":4490922,"creation_time":"2010-01-17T01:13:33Z"},{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":4487552,"creation_time":"2010-01-14T17:46:11Z"},{"is_private":false,"creator":{"real_name":"David E. Ross","name":"david"},"text":"","id":4486520,"creation_time":"2010-01-14T00:08:41Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":4486434,"creation_time":"2010-01-13T23:06:25Z"},{"is_private":false,"creator":{"real_name":"XtC4UaLL [:xtc4uall]","name":"xtc4uall"},"text":"","id":4486282,"creation_time":"2010-01-13T21:34:20Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":4486275,"creation_time":"2010-01-13T21:31:14Z"},{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":4486171,"creation_time":"2010-01-13T20:37:30Z"}],"id":539524},"events":[{"time":"2011-07-18T12:06:33Z","changeset":{"changes":[{"removed":"","added":"jwatt@jwatt.org","field_name":"cc"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jwatt@jwatt.org","name":"jwatt@jwatt.org"},"change_time":"2011-07-18T12:06:33Z"}}]},{"bug":{"history":[{"changes":[{"removed":"","added":"568943","field_name":"blocks"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-07-18T09:21:42Z"},{"changes":[{"removed":"[mozmill-next?]","added":"[mozmill-2.0-][mozmill-next?]","field_name":"whiteboard"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-05-25T12:01:37Z"},{"changes":[{"removed":"[mozmill-2.0+]","added":"[mozmill-next?]","field_name":"whiteboard"},{"removed":"critical","added":"normal","field_name":"severity"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-05-24T22:41:14Z"},{"changes":[{"removed":"[mozmill-2.0?]","added":"[mozmill-2.0+]","field_name":"whiteboard"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/ctalbert@mozilla.com","name":"ctalbert@mozilla.com"},"change_time":"2011-03-29T21:43:13Z"},{"changes":[{"removed":"","added":"dataloss","field_name":"keywords"},{"removed":"enhancement","added":"critical","field_name":"severity"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-03-21T00:24:58Z"},{"changes":[{"removed":"nobody@mozilla.org","added":"jhammel@mozilla.com","field_name":"assigned_to"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-03-18T21:05:30Z"},{"changes":[{"removed":"","added":"ahalberstadt@mozilla.com, ctalbert@mozilla.com, fayearthur+bugs@gmail.com, hskupin@gmail.com","field_name":"cc"},{"removed":"","added":"[mozmill-2.0?]","field_name":"whiteboard"},{"removed":"normal","added":"enhancement","field_name":"severity"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/jhammel@mozilla.com","name":"jhammel@mozilla.com"},"change_time":"2011-03-18T16:29:22Z"}],"summary":"should be able to clone from a profile as a basis","last_change_time":"2011-07-18T09:21:42Z","comments":[{"is_private":false,"creator":{"real_name":"Clint Talbert ( :ctalbert )","name":"ctalbert"},"text":"","id":5490872,"creation_time":"2011-05-24T22:41:14Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5357384,"creation_time":"2011-03-21T16:41:15Z"},{"is_private":false,"creator":{"real_name":"Henrik Skupin (:whimboo)","name":"hskupin"},"text":"","id":5356453,"creation_time":"2011-03-21T00:24:58Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5353489,"creation_time":"2011-03-18T16:32:57Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5353480,"creation_time":"2011-03-18T16:29:22Z"},{"is_private":false,"creator":{"real_name":"Jeff Hammel [:jhammel]","name":"jhammel"},"text":"","id":5353472,"creation_time":"2011-03-18T16:27:14Z"}],"id":642843},"events":[{"time":"2011-07-18T09:21:42Z","changeset":{"changes":[{"removed":"","added":"568943","field_name":"blocks"}],"changer":{"ref":"https://api-dev.bugzilla.mozilla.org/0.9/user/hskupin@gmail.com","name":"hskupin@gmail.com"},"change_time":"2011-07-18T09:21:42Z"}}]}] --------------------------------------------------------------------------------