diff --git a/pkg/fileembed/fileembed.go b/pkg/fileembed/fileembed.go index 8335f12ce..7d4b8a5d9 100644 --- a/pkg/fileembed/fileembed.go +++ b/pkg/fileembed/fileembed.go @@ -18,7 +18,6 @@ package fileembed import ( "errors" - "fmt" "io" "io/ioutil" "net/http" @@ -28,8 +27,6 @@ import ( "time" ) -var binaryModTime = statBinaryModTime() - type Files struct { // Optional environment variable key to override OverrideEnv string @@ -42,22 +39,32 @@ type Files struct { SlurpToMemory bool lk sync.Mutex - file map[string]string + file map[string]*staticFile +} + +type staticFile struct { + name string + contents string + modtime time.Time } // Add adds a file to the file set. -func (f *Files) Add(filename, body string) { +func (f *Files) Add(filename, contents string, modtime time.Time) { f.lk.Lock() defer f.lk.Unlock() - f.add(filename, body) + f.add(filename, &staticFile{ + name: filename, + contents: contents, + modtime: modtime, + }) } // f.lk must be locked -func (f *Files) add(filename, body string) { +func (f *Files) add(filename string, sf *staticFile) { if f.file == nil { - f.file = make(map[string]string) + f.file = make(map[string]*staticFile) } - f.file[filename] = body + f.file[filename] = sf } func (f *Files) Open(filename string) (http.File, error) { @@ -66,11 +73,11 @@ func (f *Files) Open(filename string) (http.File, error) { } f.lk.Lock() defer f.lk.Unlock() - s, ok := f.file[filename] + sf, ok := f.file[filename] if !ok { return f.openFallback(filename) } - return &file{name: filename, s: s}, nil + return &fileHandle{sf: sf}, nil } // f.lk is held @@ -88,22 +95,29 @@ func (f *Files) openFallback(filename string) (http.File, error) { if err != nil { return nil, err } + fi, err := of.Stat() + s := string(bs) - f.add(filename, s) - return &file{name: filename, s: s}, nil + sf := &staticFile{ + name: filename, + contents: s, + modtime: fi.ModTime(), + } + f.add(filename, sf) + return &fileHandle{sf: sf}, nil } return of, nil } -type file struct { - name string - s string - +type fileHandle struct { + sf *staticFile off int64 closed bool } -func (f *file) Close() error { +var _ http.File = (*fileHandle)(nil) + +func (f *fileHandle) Close() error { if f.closed { return os.ErrInvalid } @@ -111,27 +125,27 @@ func (f *file) Close() error { return nil } -func (f *file) Read(p []byte) (n int, err error) { - if f.off >= int64(len(f.s)) { +func (f *fileHandle) Read(p []byte) (n int, err error) { + if f.off >= int64(len(f.sf.contents)) { return 0, io.EOF } - n = copy(p, f.s[f.off:]) + n = copy(p, f.sf.contents[f.off:]) f.off += int64(n) return } -func (f *file) Readdir(int) ([]os.FileInfo, error) { +func (f *fileHandle) Readdir(int) ([]os.FileInfo, error) { return nil, errors.New("not directory") } -func (f *file) Seek(offset int64, whence int) (int64, error) { +func (f *fileHandle) Seek(offset int64, whence int) (int64, error) { switch whence { case os.SEEK_SET: f.off = offset case os.SEEK_CUR: f.off += offset case os.SEEK_END: - f.off = int64(len(f.s)) + offset + f.off = int64(len(f.sf.contents)) + offset default: return 0, os.ErrInvalid } @@ -141,31 +155,15 @@ func (f *file) Seek(offset int64, whence int) (int64, error) { return f.off, nil } -type fileInfo struct { - name string - size int64 - modtime time.Time +func (f *fileHandle) Stat() (os.FileInfo, error) { + return f.sf, nil } -func (fi *fileInfo) Name() string { return fi.name } -func (fi *fileInfo) Size() int64 { return fi.size } -func (fi *fileInfo) Mode() os.FileMode { return 0444 } -func (fi *fileInfo) ModTime() time.Time { return fi.modtime } -func (fi *fileInfo) IsDir() bool { return false } -func (fi *fileInfo) Sys() interface{} { return nil } +var _ os.FileInfo = (*staticFile)(nil) -func (f *file) Stat() (os.FileInfo, error) { - return &fileInfo{ - name: f.name, - size: int64(len(f.s)), - modtime: binaryModTime, - }, nil -} - -func statBinaryModTime() time.Time { - fi, err := os.Stat(os.Args[0]) - if err != nil { - panic(fmt.Sprintf("Failed to stat binary %q: %v", os.Args[0], err)) - } - return fi.ModTime() -} +func (f *staticFile) Name() string { return f.name } +func (f *staticFile) Size() int64 { return int64(len(f.contents)) } +func (f *staticFile) Mode() os.FileMode { return 0444 } +func (f *staticFile) ModTime() time.Time { return f.modtime } +func (f *staticFile) IsDir() bool { return false } +func (f *staticFile) Sys() interface{} { return nil } diff --git a/pkg/fileembed/genfileembed/genfileembed.go b/pkg/fileembed/genfileembed/genfileembed.go index 9a1160e05..cdd58eace 100644 --- a/pkg/fileembed/genfileembed/genfileembed.go +++ b/pkg/fileembed/genfileembed/genfileembed.go @@ -49,6 +49,7 @@ func main() { if err != nil { log.Fatalf("Error parsing %s/fileembed.go: %v", dir, err) } + for _, fileName := range matchingFiles(filePattern) { embedName := "zembed_" + fileName + ".go" fi, err := os.Stat(fileName) @@ -68,7 +69,8 @@ func main() { fmt.Fprintf(&b, "// THIS FILE IS AUTO-GENERATED FROM %s\n", fileName) fmt.Fprintf(&b, "// DO NOT EDIT.\n") fmt.Fprintf(&b, "package %s\n", pkgName) - fmt.Fprintf(&b, "func init() {\n\tFiles.Add(%q, %q);\n}\n", fileName, bs) + fmt.Fprintf(&b, "import \"time\"\n") + fmt.Fprintf(&b, "func init() {\n\tFiles.Add(%q, %q, time.Unix(0, %d));\n}\n", fileName, bs, fi.ModTime().UnixNano()) if err := ioutil.WriteFile(embedName, b.Bytes(), 0644); err != nil { log.Fatal(err) } diff --git a/server/camlistored/ui/zembed_Crypto.js.go b/server/camlistored/ui/zembed_Crypto.js.go index eb01a6590..faa9491c5 100644 --- a/server/camlistored/ui/zembed_Crypto.js.go +++ b/server/camlistored/ui/zembed_Crypto.js.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM Crypto.js // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("Crypto.js", "// From http://code.google.com/p/crypto-js/\r\n// License: http://www.opensource.org/licenses/bsd-license.php\r\n//\r\n// Copyright (c) 2009, Jeff Mott. All rights reserved.\r\n// \r\n// Redistribution and use in source and binary forms, with or without\r\n// modification, are permitted provided that the following conditions are met:\r\n// \r\n// Redistributions of source code must retain the above copyright notice, this\r\n// list of conditions and the following disclaimer. Redistributions in binary\r\n// form must reproduce the above copyright notice, this list of conditions and\r\n// the following disclaimer in the documentation and/or other materials provided\r\n// with the distribution. Neither the name Crypto-JS nor the names of its\r\n// contributors may be used to endorse or promote products derived from this\r\n// software without specific prior written permission. THIS SOFTWARE IS PROVIDED\r\n// BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED\r\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\r\n// EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\r\n// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n\r\nif (typeof Crypto == \"undefined\" || ! Crypto.util)\r\n{\r\n(function(){\r\n\r\nvar base64map = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\r\n\r\n// Global Crypto object\r\nvar Crypto = window.Crypto = {};\r\n\r\n// Crypto utilities\r\nvar util = Crypto.util = {\r\n\r\n\t// Bit-wise rotate left\r\n\trotl: function (n, b) {\r\n\t\treturn (n << b) | (n >>> (32 - b));\r\n\t},\r\n\r\n\t// Bit-wise rotate right\r\n\trotr: function (n, b) {\r\n\t\treturn (n << (32 - b)) | (n >>> b);\r\n\t},\r\n\r\n\t// Swap big-endian to little-endian and vice versa\r\n\tendian: function (n) {\r\n\r\n\t\t// If number given, swap endian\r\n\t\tif (n.constructor == Number) {\r\n\t\t\treturn util.rotl(n, 8) & 0x00FF00FF |\r\n\t\t\t util.rotl(n, 24) & 0xFF00FF00;\r\n\t\t}\r\n\r\n\t\t// Else, assume array and swap all items\r\n\t\tfor (var i = 0; i < n.length; i++)\r\n\t\t\tn[i] = util.endian(n[i]);\r\n\t\treturn n;\r\n\r\n\t},\r\n\r\n\t// Generate an array of any length of random bytes\r\n\trandomBytes: function (n) {\r\n\t\tfor (var bytes = []; n > 0; n--)\r\n\t\t\tbytes.push(Math.floor(Math.random() * 256));\r\n\t\treturn bytes;\r\n\t},\r\n\r\n\t// Convert a byte array to big-endian 32-bit words\r\n\tbytesToWords: function (bytes) {\r\n\t\tfor (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)\r\n\t\t\twords[b >>> 5] |= bytes[i] << (24 - b % 32);\r\n\t\treturn words;\r\n\t},\r\n\r\n\t// Convert big-endian 32-bit words to a byte array\r\n\twordsToBytes: function (words) {\r\n\t\tfor (var bytes = [], b = 0; b < words.length * 32; b += 8)\r\n\t\t\tbytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);\r\n\t\treturn bytes;\r\n\t},\r\n\r\n\t// Convert a byte array to a hex string\r\n\tbytesToHex: function (bytes) {\r\n\t\tfor (var hex = [], i = 0; i < bytes.length; i++) {\r\n\t\t\thex.push((bytes[i] >>> 4).toString(16));\r\n\t\t\thex.push((bytes[i] & 0xF).toString(16));\r\n\t\t}\r\n\t\treturn hex.join(\"\");\r\n\t},\r\n\r\n\t// Convert a hex string to a byte array\r\n\thexToBytes: function (hex) {\r\n\t\tfor (var bytes = [], c = 0; c < hex.length; c += 2)\r\n\t\t\tbytes.push(parseInt(hex.substr(c, 2), 16));\r\n\t\treturn bytes;\r\n\t},\r\n\r\n\t// Convert a byte array to a base-64 string\r\n\tbytesToBase64: function (bytes) {\r\n\r\n\t\t// Use browser-native function if it exists\r\n\t\tif (typeof btoa == \"function\") return btoa(Binary.bytesToString(bytes));\r\n\r\n\t\tfor(var base64 = [], i = 0; i < bytes.length; i += 3) {\r\n\t\t\tvar triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];\r\n\t\t\tfor (var j = 0; j < 4; j++) {\r\n\t\t\t\tif (i * 8 + j * 6 <= bytes.length * 8)\r\n\t\t\t\t\tbase64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));\r\n\t\t\t\telse base64.push(\"=\");\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn base64.join(\"\");\r\n\r\n\t},\r\n\r\n\t// Convert a base-64 string to a byte array\r\n\tbase64ToBytes: function (base64) {\r\n\r\n\t\t// Use browser-native function if it exists\r\n\t\tif (typeof atob == \"function\") return Binary.stringToBytes(atob(base64));\r\n\r\n\t\t// Remove non-base-64 characters\r\n\t\tbase64 = base64.replace(/[^A-Z0-9+\\/]/ig, \"\");\r\n\r\n\t\tfor (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) {\r\n\t\t\tif (imod4 == 0) continue;\r\n\t\t\tbytes.push(((base64map.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) |\r\n\t\t\t (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2)));\r\n\t\t}\r\n\r\n\t\treturn bytes;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// Crypto mode namespace\r\nCrypto.mode = {};\r\n\r\n// Crypto character encodings\r\nvar charenc = Crypto.charenc = {};\r\n\r\n// UTF-8 encoding\r\nvar UTF8 = charenc.UTF8 = {\r\n\r\n\t// Convert a string to a byte array\r\n\tstringToBytes: function (str) {\r\n\t\treturn Binary.stringToBytes(unescape(encodeURIComponent(str)));\r\n\t},\r\n\r\n\t// Convert a byte array to a string\r\n\tbytesToString: function (bytes) {\r\n\t\treturn decodeURIComponent(escape(Binary.bytesToString(bytes)));\r\n\t}\r\n\r\n};\r\n\r\n// Binary encoding\r\nvar Binary = charenc.Binary = {\r\n\r\n\t// Convert a string to a byte array\r\n\tstringToBytes: function (str) {\r\n\t\tfor (var bytes = [], i = 0; i < str.length; i++)\r\n\t\t\tbytes.push(str.charCodeAt(i));\r\n\t\treturn bytes;\r\n\t},\r\n\r\n\t// Convert a byte array to a string\r\n\tbytesToString: function (bytes) {\r\n\t\tfor (var str = [], i = 0; i < bytes.length; i++)\r\n\t\t\tstr.push(String.fromCharCode(bytes[i]));\r\n\t\treturn str.join(\"\");\r\n\t}\r\n\r\n};\r\n\r\n})();\r\n}\r\n"); + Files.Add("Crypto.js", "// From http://code.google.com/p/crypto-js/\r\n// License: http://www.opensource.org/licenses/bsd-license.php\r\n//\r\n// Copyright (c) 2009, Jeff Mott. All rights reserved.\r\n// \r\n// Redistribution and use in source and binary forms, with or without\r\n// modification, are permitted provided that the following conditions are met:\r\n// \r\n// Redistributions of source code must retain the above copyright notice, this\r\n// list of conditions and the following disclaimer. Redistributions in binary\r\n// form must reproduce the above copyright notice, this list of conditions and\r\n// the following disclaimer in the documentation and/or other materials provided\r\n// with the distribution. Neither the name Crypto-JS nor the names of its\r\n// contributors may be used to endorse or promote products derived from this\r\n// software without specific prior written permission. THIS SOFTWARE IS PROVIDED\r\n// BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED\r\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\r\n// EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\r\n// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n\r\nif (typeof Crypto == \"undefined\" || ! Crypto.util)\r\n{\r\n(function(){\r\n\r\nvar base64map = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\r\n\r\n// Global Crypto object\r\nvar Crypto = window.Crypto = {};\r\n\r\n// Crypto utilities\r\nvar util = Crypto.util = {\r\n\r\n\t// Bit-wise rotate left\r\n\trotl: function (n, b) {\r\n\t\treturn (n << b) | (n >>> (32 - b));\r\n\t},\r\n\r\n\t// Bit-wise rotate right\r\n\trotr: function (n, b) {\r\n\t\treturn (n << (32 - b)) | (n >>> b);\r\n\t},\r\n\r\n\t// Swap big-endian to little-endian and vice versa\r\n\tendian: function (n) {\r\n\r\n\t\t// If number given, swap endian\r\n\t\tif (n.constructor == Number) {\r\n\t\t\treturn util.rotl(n, 8) & 0x00FF00FF |\r\n\t\t\t util.rotl(n, 24) & 0xFF00FF00;\r\n\t\t}\r\n\r\n\t\t// Else, assume array and swap all items\r\n\t\tfor (var i = 0; i < n.length; i++)\r\n\t\t\tn[i] = util.endian(n[i]);\r\n\t\treturn n;\r\n\r\n\t},\r\n\r\n\t// Generate an array of any length of random bytes\r\n\trandomBytes: function (n) {\r\n\t\tfor (var bytes = []; n > 0; n--)\r\n\t\t\tbytes.push(Math.floor(Math.random() * 256));\r\n\t\treturn bytes;\r\n\t},\r\n\r\n\t// Convert a byte array to big-endian 32-bit words\r\n\tbytesToWords: function (bytes) {\r\n\t\tfor (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)\r\n\t\t\twords[b >>> 5] |= bytes[i] << (24 - b % 32);\r\n\t\treturn words;\r\n\t},\r\n\r\n\t// Convert big-endian 32-bit words to a byte array\r\n\twordsToBytes: function (words) {\r\n\t\tfor (var bytes = [], b = 0; b < words.length * 32; b += 8)\r\n\t\t\tbytes.push((words[b >>> 5] >>> (24 - b % 32)) & 0xFF);\r\n\t\treturn bytes;\r\n\t},\r\n\r\n\t// Convert a byte array to a hex string\r\n\tbytesToHex: function (bytes) {\r\n\t\tfor (var hex = [], i = 0; i < bytes.length; i++) {\r\n\t\t\thex.push((bytes[i] >>> 4).toString(16));\r\n\t\t\thex.push((bytes[i] & 0xF).toString(16));\r\n\t\t}\r\n\t\treturn hex.join(\"\");\r\n\t},\r\n\r\n\t// Convert a hex string to a byte array\r\n\thexToBytes: function (hex) {\r\n\t\tfor (var bytes = [], c = 0; c < hex.length; c += 2)\r\n\t\t\tbytes.push(parseInt(hex.substr(c, 2), 16));\r\n\t\treturn bytes;\r\n\t},\r\n\r\n\t// Convert a byte array to a base-64 string\r\n\tbytesToBase64: function (bytes) {\r\n\r\n\t\t// Use browser-native function if it exists\r\n\t\tif (typeof btoa == \"function\") return btoa(Binary.bytesToString(bytes));\r\n\r\n\t\tfor(var base64 = [], i = 0; i < bytes.length; i += 3) {\r\n\t\t\tvar triplet = (bytes[i] << 16) | (bytes[i + 1] << 8) | bytes[i + 2];\r\n\t\t\tfor (var j = 0; j < 4; j++) {\r\n\t\t\t\tif (i * 8 + j * 6 <= bytes.length * 8)\r\n\t\t\t\t\tbase64.push(base64map.charAt((triplet >>> 6 * (3 - j)) & 0x3F));\r\n\t\t\t\telse base64.push(\"=\");\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn base64.join(\"\");\r\n\r\n\t},\r\n\r\n\t// Convert a base-64 string to a byte array\r\n\tbase64ToBytes: function (base64) {\r\n\r\n\t\t// Use browser-native function if it exists\r\n\t\tif (typeof atob == \"function\") return Binary.stringToBytes(atob(base64));\r\n\r\n\t\t// Remove non-base-64 characters\r\n\t\tbase64 = base64.replace(/[^A-Z0-9+\\/]/ig, \"\");\r\n\r\n\t\tfor (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) {\r\n\t\t\tif (imod4 == 0) continue;\r\n\t\t\tbytes.push(((base64map.indexOf(base64.charAt(i - 1)) & (Math.pow(2, -2 * imod4 + 8) - 1)) << (imod4 * 2)) |\r\n\t\t\t (base64map.indexOf(base64.charAt(i)) >>> (6 - imod4 * 2)));\r\n\t\t}\r\n\r\n\t\treturn bytes;\r\n\r\n\t}\r\n\r\n};\r\n\r\n// Crypto mode namespace\r\nCrypto.mode = {};\r\n\r\n// Crypto character encodings\r\nvar charenc = Crypto.charenc = {};\r\n\r\n// UTF-8 encoding\r\nvar UTF8 = charenc.UTF8 = {\r\n\r\n\t// Convert a string to a byte array\r\n\tstringToBytes: function (str) {\r\n\t\treturn Binary.stringToBytes(unescape(encodeURIComponent(str)));\r\n\t},\r\n\r\n\t// Convert a byte array to a string\r\n\tbytesToString: function (bytes) {\r\n\t\treturn decodeURIComponent(escape(Binary.bytesToString(bytes)));\r\n\t}\r\n\r\n};\r\n\r\n// Binary encoding\r\nvar Binary = charenc.Binary = {\r\n\r\n\t// Convert a string to a byte array\r\n\tstringToBytes: function (str) {\r\n\t\tfor (var bytes = [], i = 0; i < str.length; i++)\r\n\t\t\tbytes.push(str.charCodeAt(i));\r\n\t\treturn bytes;\r\n\t},\r\n\r\n\t// Convert a byte array to a string\r\n\tbytesToString: function (bytes) {\r\n\t\tfor (var str = [], i = 0; i < bytes.length; i++)\r\n\t\t\tstr.push(String.fromCharCode(bytes[i]));\r\n\t\treturn str.join(\"\");\r\n\t}\r\n\r\n};\r\n\r\n})();\r\n}\r\n", time.Unix(0, 1307659868000000000)); } diff --git a/server/camlistored/ui/zembed_SHA1.js.go b/server/camlistored/ui/zembed_SHA1.js.go index 5712f68ad..70b0cdcf2 100644 --- a/server/camlistored/ui/zembed_SHA1.js.go +++ b/server/camlistored/ui/zembed_SHA1.js.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM SHA1.js // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("SHA1.js", "// From http://code.google.com/p/crypto-js/\r\n// License: http://www.opensource.org/licenses/bsd-license.php\r\n//\r\n// Copyright (c) 2009, Jeff Mott. All rights reserved.\r\n// \r\n// Redistribution and use in source and binary forms, with or without\r\n// modification, are permitted provided that the following conditions are met:\r\n// \r\n// Redistributions of source code must retain the above copyright notice, this\r\n// list of conditions and the following disclaimer. Redistributions in binary\r\n// form must reproduce the above copyright notice, this list of conditions and\r\n// the following disclaimer in the documentation and/or other materials provided\r\n// with the distribution. Neither the name Crypto-JS nor the names of its\r\n// contributors may be used to endorse or promote products derived from this\r\n// software without specific prior written permission. THIS SOFTWARE IS PROVIDED\r\n// BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED\r\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\r\n// EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\r\n// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n\r\n(function(){\r\n\r\n// Shortcuts\r\nvar C = Crypto,\r\n util = C.util,\r\n charenc = C.charenc,\r\n UTF8 = charenc.UTF8,\r\n Binary = charenc.Binary;\r\n\r\n// Public API\r\nvar SHA1 = C.SHA1 = function (message, options) {\r\n\tvar digestbytes = util.wordsToBytes(SHA1._sha1(message));\r\n\treturn options && options.asBytes ? digestbytes :\r\n\t options && options.asString ? Binary.bytesToString(digestbytes) :\r\n\t util.bytesToHex(digestbytes);\r\n};\r\n\r\n// The core\r\nSHA1._sha1 = function (message) {\r\n\r\n\t// Convert to byte array\r\n\tif (message.constructor == String) message = UTF8.stringToBytes(message);\r\n\t/* else, assume byte array already */\r\n\r\n\tvar m = util.bytesToWords(message),\r\n\t l = message.length * 8,\r\n\t w = [],\r\n\t H0 = 1732584193,\r\n\t H1 = -271733879,\r\n\t H2 = -1732584194,\r\n\t H3 = 271733878,\r\n\t H4 = -1009589776;\r\n\r\n\t// Padding\r\n\tm[l >> 5] |= 0x80 << (24 - l % 32);\r\n\tm[((l + 64 >>> 9) << 4) + 15] = l;\r\n\r\n\tfor (var i = 0; i < m.length; i += 16) {\r\n\r\n\t\tvar a = H0,\r\n\t\t b = H1,\r\n\t\t c = H2,\r\n\t\t d = H3,\r\n\t\t e = H4;\r\n\r\n\t\tfor (var j = 0; j < 80; j++) {\r\n\r\n\t\t\tif (j < 16) w[j] = m[i + j];\r\n\t\t\telse {\r\n\t\t\t\tvar n = w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16];\r\n\t\t\t\tw[j] = (n << 1) | (n >>> 31);\r\n\t\t\t}\r\n\r\n\t\t\tvar t = ((H0 << 5) | (H0 >>> 27)) + H4 + (w[j] >>> 0) + (\r\n\t\t\t j < 20 ? (H1 & H2 | ~H1 & H3) + 1518500249 :\r\n\t\t\t j < 40 ? (H1 ^ H2 ^ H3) + 1859775393 :\r\n\t\t\t j < 60 ? (H1 & H2 | H1 & H3 | H2 & H3) - 1894007588 :\r\n\t\t\t (H1 ^ H2 ^ H3) - 899497514);\r\n\r\n\t\t\tH4 = H3;\r\n\t\t\tH3 = H2;\r\n\t\t\tH2 = (H1 << 30) | (H1 >>> 2);\r\n\t\t\tH1 = H0;\r\n\t\t\tH0 = t;\r\n\r\n\t\t}\r\n\r\n\t\tH0 += a;\r\n\t\tH1 += b;\r\n\t\tH2 += c;\r\n\t\tH3 += d;\r\n\t\tH4 += e;\r\n\r\n\t}\r\n\r\n\treturn [H0, H1, H2, H3, H4];\r\n\r\n};\r\n\r\n// Package private blocksize\r\nSHA1._blocksize = 16;\r\n\r\n})();\r\n"); + Files.Add("SHA1.js", "// From http://code.google.com/p/crypto-js/\r\n// License: http://www.opensource.org/licenses/bsd-license.php\r\n//\r\n// Copyright (c) 2009, Jeff Mott. All rights reserved.\r\n// \r\n// Redistribution and use in source and binary forms, with or without\r\n// modification, are permitted provided that the following conditions are met:\r\n// \r\n// Redistributions of source code must retain the above copyright notice, this\r\n// list of conditions and the following disclaimer. Redistributions in binary\r\n// form must reproduce the above copyright notice, this list of conditions and\r\n// the following disclaimer in the documentation and/or other materials provided\r\n// with the distribution. Neither the name Crypto-JS nor the names of its\r\n// contributors may be used to endorse or promote products derived from this\r\n// software without specific prior written permission. THIS SOFTWARE IS PROVIDED\r\n// BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED\r\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\r\n// EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\r\n// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\r\n// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r\n// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\r\n// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r\n// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r\n// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r\n\r\n(function(){\r\n\r\n// Shortcuts\r\nvar C = Crypto,\r\n util = C.util,\r\n charenc = C.charenc,\r\n UTF8 = charenc.UTF8,\r\n Binary = charenc.Binary;\r\n\r\n// Public API\r\nvar SHA1 = C.SHA1 = function (message, options) {\r\n\tvar digestbytes = util.wordsToBytes(SHA1._sha1(message));\r\n\treturn options && options.asBytes ? digestbytes :\r\n\t options && options.asString ? Binary.bytesToString(digestbytes) :\r\n\t util.bytesToHex(digestbytes);\r\n};\r\n\r\n// The core\r\nSHA1._sha1 = function (message) {\r\n\r\n\t// Convert to byte array\r\n\tif (message.constructor == String) message = UTF8.stringToBytes(message);\r\n\t/* else, assume byte array already */\r\n\r\n\tvar m = util.bytesToWords(message),\r\n\t l = message.length * 8,\r\n\t w = [],\r\n\t H0 = 1732584193,\r\n\t H1 = -271733879,\r\n\t H2 = -1732584194,\r\n\t H3 = 271733878,\r\n\t H4 = -1009589776;\r\n\r\n\t// Padding\r\n\tm[l >> 5] |= 0x80 << (24 - l % 32);\r\n\tm[((l + 64 >>> 9) << 4) + 15] = l;\r\n\r\n\tfor (var i = 0; i < m.length; i += 16) {\r\n\r\n\t\tvar a = H0,\r\n\t\t b = H1,\r\n\t\t c = H2,\r\n\t\t d = H3,\r\n\t\t e = H4;\r\n\r\n\t\tfor (var j = 0; j < 80; j++) {\r\n\r\n\t\t\tif (j < 16) w[j] = m[i + j];\r\n\t\t\telse {\r\n\t\t\t\tvar n = w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16];\r\n\t\t\t\tw[j] = (n << 1) | (n >>> 31);\r\n\t\t\t}\r\n\r\n\t\t\tvar t = ((H0 << 5) | (H0 >>> 27)) + H4 + (w[j] >>> 0) + (\r\n\t\t\t j < 20 ? (H1 & H2 | ~H1 & H3) + 1518500249 :\r\n\t\t\t j < 40 ? (H1 ^ H2 ^ H3) + 1859775393 :\r\n\t\t\t j < 60 ? (H1 & H2 | H1 & H3 | H2 & H3) - 1894007588 :\r\n\t\t\t (H1 ^ H2 ^ H3) - 899497514);\r\n\r\n\t\t\tH4 = H3;\r\n\t\t\tH3 = H2;\r\n\t\t\tH2 = (H1 << 30) | (H1 >>> 2);\r\n\t\t\tH1 = H0;\r\n\t\t\tH0 = t;\r\n\r\n\t\t}\r\n\r\n\t\tH0 += a;\r\n\t\tH1 += b;\r\n\t\tH2 += c;\r\n\t\tH3 += d;\r\n\t\tH4 += e;\r\n\r\n\t}\r\n\r\n\treturn [H0, H1, H2, H3, H4];\r\n\r\n};\r\n\r\n// Package private blocksize\r\nSHA1._blocksize = 16;\r\n\r\n})();\r\n", time.Unix(0, 1307659868000000000)); } diff --git a/server/camlistored/ui/zembed_base64.js.go b/server/camlistored/ui/zembed_base64.js.go index 54c589773..74cac9deb 100644 --- a/server/camlistored/ui/zembed_base64.js.go +++ b/server/camlistored/ui/zembed_base64.js.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM base64.js // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("base64.js", "/*\nCopyright (c) 2008 Fred Palmer fred.palmer_at_gmail.com\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n*/\nfunction StringBuffer()\n{ \n this.buffer = []; \n} \n\nStringBuffer.prototype.append = function append(string)\n{ \n this.buffer.push(string); \n return this; \n}; \n\nStringBuffer.prototype.toString = function toString()\n{ \n return this.buffer.join(\"\"); \n}; \n\nvar Base64 =\n{\n codex : \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",\n\n encode : function (input)\n {\n var output = new StringBuffer();\n\n var enumerator = new Utf8EncodeEnumerator(input);\n while (enumerator.moveNext())\n {\n var chr1 = enumerator.current;\n\n enumerator.moveNext();\n var chr2 = enumerator.current;\n\n enumerator.moveNext();\n var chr3 = enumerator.current;\n\n var enc1 = chr1 >> 2;\n var enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n var enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n var enc4 = chr3 & 63;\n\n if (isNaN(chr2))\n {\n enc3 = enc4 = 64;\n }\n else if (isNaN(chr3))\n {\n enc4 = 64;\n }\n\n output.append(this.codex.charAt(enc1) + this.codex.charAt(enc2) + this.codex.charAt(enc3) + this.codex.charAt(enc4));\n }\n\n return output.toString();\n },\n\n decode : function (input)\n {\n // TypedArray usage added by brett@haxor.com 11/27/2010\n var size = 0;\n var buffer = new ArrayBuffer(input.length);\n var output = new Uint8Array(buffer, 0);\n\n var enumerator = new Base64DecodeEnumerator(input);\n while (enumerator.moveNext()) {\n output[size++] = enumerator.current;\n }\n\n // There is nothing in the TypedArray spec to copy/subset a buffer,\n // so we have to do a copy to ensure that typedarray.buffer is the\n // correct length when passed to XmlHttpRequest methods, etc.\n var outputBuffer = new ArrayBuffer(size);\n var outputArray = new Uint8Array(outputBuffer, 0);\n for (var i = 0; i < size; i++) {\n outputArray[i] = output[i];\n }\n return outputArray;\n }\n}\n\n\nfunction Utf8EncodeEnumerator(input)\n{\n this._input = input;\n this._index = -1;\n this._buffer = [];\n}\n\nUtf8EncodeEnumerator.prototype =\n{\n current: Number.NaN,\n\n moveNext: function()\n {\n if (this._buffer.length > 0)\n {\n this.current = this._buffer.shift();\n return true;\n }\n else if (this._index >= (this._input.length - 1))\n {\n this.current = Number.NaN;\n return false;\n }\n else\n {\n var charCode = this._input.charCodeAt(++this._index);\n\n // \"\\r\\n\" -> \"\\n\"\n //\n if ((charCode == 13) && (this._input.charCodeAt(this._index + 1) == 10))\n {\n charCode = 10;\n this._index += 2;\n }\n\n if (charCode < 128)\n {\n this.current = charCode;\n }\n else if ((charCode > 127) && (charCode < 2048))\n {\n this.current = (charCode >> 6) | 192;\n this._buffer.push((charCode & 63) | 128);\n }\n else\n {\n this.current = (charCode >> 12) | 224;\n this._buffer.push(((charCode >> 6) & 63) | 128);\n this._buffer.push((charCode & 63) | 128);\n }\n\n return true;\n }\n }\n}\n\nfunction Base64DecodeEnumerator(input)\n{\n this._input = input;\n this._index = -1;\n this._buffer = [];\n}\n\nBase64DecodeEnumerator.prototype =\n{\n current: 64,\n\n moveNext: function()\n {\n if (this._buffer.length > 0)\n {\n this.current = this._buffer.shift();\n return true;\n }\n else if (this._index >= (this._input.length - 1))\n {\n this.current = 64;\n return false;\n }\n else\n {\n var enc1 = Base64.codex.indexOf(this._input.charAt(++this._index));\n var enc2 = Base64.codex.indexOf(this._input.charAt(++this._index));\n var enc3 = Base64.codex.indexOf(this._input.charAt(++this._index));\n var enc4 = Base64.codex.indexOf(this._input.charAt(++this._index));\n\n var chr1 = (enc1 << 2) | (enc2 >> 4);\n var chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n var chr3 = ((enc3 & 3) << 6) | enc4;\n\n this.current = chr1;\n\n if (enc3 != 64)\n this._buffer.push(chr2);\n\n if (enc4 != 64)\n this._buffer.push(chr3);\n\n return true;\n }\n }\n};\n"); + Files.Add("base64.js", "/*\nCopyright (c) 2008 Fred Palmer fred.palmer_at_gmail.com\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n*/\nfunction StringBuffer()\n{ \n this.buffer = []; \n} \n\nStringBuffer.prototype.append = function append(string)\n{ \n this.buffer.push(string); \n return this; \n}; \n\nStringBuffer.prototype.toString = function toString()\n{ \n return this.buffer.join(\"\"); \n}; \n\nvar Base64 =\n{\n codex : \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\",\n\n encode : function (input)\n {\n var output = new StringBuffer();\n\n var enumerator = new Utf8EncodeEnumerator(input);\n while (enumerator.moveNext())\n {\n var chr1 = enumerator.current;\n\n enumerator.moveNext();\n var chr2 = enumerator.current;\n\n enumerator.moveNext();\n var chr3 = enumerator.current;\n\n var enc1 = chr1 >> 2;\n var enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);\n var enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);\n var enc4 = chr3 & 63;\n\n if (isNaN(chr2))\n {\n enc3 = enc4 = 64;\n }\n else if (isNaN(chr3))\n {\n enc4 = 64;\n }\n\n output.append(this.codex.charAt(enc1) + this.codex.charAt(enc2) + this.codex.charAt(enc3) + this.codex.charAt(enc4));\n }\n\n return output.toString();\n },\n\n decode : function (input)\n {\n // TypedArray usage added by brett@haxor.com 11/27/2010\n var size = 0;\n var buffer = new ArrayBuffer(input.length);\n var output = new Uint8Array(buffer, 0);\n\n var enumerator = new Base64DecodeEnumerator(input);\n while (enumerator.moveNext()) {\n output[size++] = enumerator.current;\n }\n\n // There is nothing in the TypedArray spec to copy/subset a buffer,\n // so we have to do a copy to ensure that typedarray.buffer is the\n // correct length when passed to XmlHttpRequest methods, etc.\n var outputBuffer = new ArrayBuffer(size);\n var outputArray = new Uint8Array(outputBuffer, 0);\n for (var i = 0; i < size; i++) {\n outputArray[i] = output[i];\n }\n return outputArray;\n }\n}\n\n\nfunction Utf8EncodeEnumerator(input)\n{\n this._input = input;\n this._index = -1;\n this._buffer = [];\n}\n\nUtf8EncodeEnumerator.prototype =\n{\n current: Number.NaN,\n\n moveNext: function()\n {\n if (this._buffer.length > 0)\n {\n this.current = this._buffer.shift();\n return true;\n }\n else if (this._index >= (this._input.length - 1))\n {\n this.current = Number.NaN;\n return false;\n }\n else\n {\n var charCode = this._input.charCodeAt(++this._index);\n\n // \"\\r\\n\" -> \"\\n\"\n //\n if ((charCode == 13) && (this._input.charCodeAt(this._index + 1) == 10))\n {\n charCode = 10;\n this._index += 2;\n }\n\n if (charCode < 128)\n {\n this.current = charCode;\n }\n else if ((charCode > 127) && (charCode < 2048))\n {\n this.current = (charCode >> 6) | 192;\n this._buffer.push((charCode & 63) | 128);\n }\n else\n {\n this.current = (charCode >> 12) | 224;\n this._buffer.push(((charCode >> 6) & 63) | 128);\n this._buffer.push((charCode & 63) | 128);\n }\n\n return true;\n }\n }\n}\n\nfunction Base64DecodeEnumerator(input)\n{\n this._input = input;\n this._index = -1;\n this._buffer = [];\n}\n\nBase64DecodeEnumerator.prototype =\n{\n current: 64,\n\n moveNext: function()\n {\n if (this._buffer.length > 0)\n {\n this.current = this._buffer.shift();\n return true;\n }\n else if (this._index >= (this._input.length - 1))\n {\n this.current = 64;\n return false;\n }\n else\n {\n var enc1 = Base64.codex.indexOf(this._input.charAt(++this._index));\n var enc2 = Base64.codex.indexOf(this._input.charAt(++this._index));\n var enc3 = Base64.codex.indexOf(this._input.charAt(++this._index));\n var enc4 = Base64.codex.indexOf(this._input.charAt(++this._index));\n\n var chr1 = (enc1 << 2) | (enc2 >> 4);\n var chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);\n var chr3 = ((enc3 & 3) << 6) | enc4;\n\n this.current = chr1;\n\n if (enc3 != 64)\n this._buffer.push(chr2);\n\n if (enc4 != 64)\n this._buffer.push(chr3);\n\n return true;\n }\n }\n};\n", time.Unix(0, 1307659868000000000)); } diff --git a/server/camlistored/ui/zembed_blobinfo.html.go b/server/camlistored/ui/zembed_blobinfo.html.go index 2946e29b3..0b9e31ad8 100644 --- a/server/camlistored/ui/zembed_blobinfo.html.go +++ b/server/camlistored/ui/zembed_blobinfo.html.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM blobinfo.html // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("blobinfo.html", "\n\n Blob info\n \n \n \n \n\n\n
Home
\n

Blob Contents

\n\n
\n edit\n \n \n \n\n
\n\n  

Indexer Metadata

\n
\n\n  
\n

Mutation Claims

\n
\n  
\n\n\n\n"); + Files.Add("blobinfo.html", "\n\n Blob info\n \n \n \n \n\n\n
Home
\n

Blob Contents

\n\n
\n edit\n \n \n \n\n
\n\n  

Indexer Metadata

\n
\n\n  
\n

Mutation Claims

\n
\n  
\n\n\n\n", time.Unix(0, 1311540591000000000)); } diff --git a/server/camlistored/ui/zembed_blobinfo.js.go b/server/camlistored/ui/zembed_blobinfo.js.go index 731a8247c..97c74dc55 100644 --- a/server/camlistored/ui/zembed_blobinfo.js.go +++ b/server/camlistored/ui/zembed_blobinfo.js.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM blobinfo.js // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("blobinfo.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// Gets the |p| query parameter, assuming that it looks like a blobref.\nfunction getBlobParam() {\n var blobRef = getQueryParam('b');\n return (blobRef && isPlausibleBlobRef(blobRef)) ? blobRef : null;\n}\n\nfunction blobInfoUpdate(bmap) {\n var blobmeta = document.getElementById('blobmeta');\n var bd = document.getElementById(\"blobdownload\")\n bd.innerHTML = \"\";\n var blobref = getBlobParam();\n if (!blobref) {\n alert(\"no blobref?\");\n return;\n }\n var binfo = bmap[blobref];\n if (!binfo) {\n blobmeta.innerHTML = \"(not found)\";\n return;\n }\n blobmeta.innerHTML = JSON.stringify(binfo, null, 2);\n if (binfo.camliType || (binfo.type && binfo.type.indexOf(\"text/\") == 0)) {\n camliGetBlobContents(\n blobref,\n {\n success: function(data) {\n document.getElementById(\"blobdata\").innerHTML = linkifyBlobRefs(data);\n var bb = document.getElementById('blobbrowse');\n if (binfo.camliType != \"directory\") {\n bb.style.visibility = 'hidden';\n } else {\n bb.innerHTML = \"browse\";\n }\n if (binfo.camliType == \"file\") {\n try {\n finfo = JSON.parse(data);\n bd.innerHTML = \"\";\n var fileName = finfo.fileName || blobref;\n bd.firstChild.href = \"./download/\" + blobref + \"/\" + fileName;\n if (binfo.file.mimeType.indexOf(\"image/\") == 0) {\n document.getElementById(\"thumbnail\").innerHTML = \"\";\n } else {\n document.getElementById(\"thumbnail\").innerHTML = \"\";\n }\n bd.firstChild.innerText = fileName;\n bd.innerHTML = \"download: \" + bd.innerHTML;\n } catch (x) {\n }\n }\n },\n fail: alert\n });\n } else {\n document.getElementById(\"blobdata\").innerHTML = \"Unknown/binary data\";\n }\n bd.innerHTML = \"download\";\n\n if (binfo.camliType && binfo.camliType == \"permanode\") {\n document.getElementById(\"editspan\").style.display = \"inline\";\n document.getElementById(\"editlink\").href = \"./?p=\" + blobref;\n\n var claims = document.getElementById(\"claimsdiv\");\n claims.style.visibility = \"\";\n camliGetPermanodeClaims(\n blobref,\n {\n success: function(data) {\n document.getElementById(\"claims\").innerHTML = linkifyBlobRefs(JSON.stringify(data, null, 2));\n },\n fail: function(msg) {\n alert(msg);\n }\n });\n }\n\n}\n\nfunction blobInfoOnLoad() {\n var blobref = getBlobParam();\n if (!blobref) {\n return\n }\n var blobmeta = document.getElementById('blobmeta');\n blobmeta.innerText = \"(loading)\";\n\n var blobdescribe = document.getElementById('blobdescribe');\n blobdescribe.innerHTML = \"describe\";\n camliDescribeBlob(\n blobref,\n {\n success: blobInfoUpdate,\n fail: function(msg) {\n alert(\"Error describing blob \" + blobref + \": \" + msg);\n }\n }\n );\n}\n\nwindow.addEventListener(\"load\", blobInfoOnLoad);\n"); + Files.Add("blobinfo.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// Gets the |p| query parameter, assuming that it looks like a blobref.\nfunction getBlobParam() {\n var blobRef = getQueryParam('b');\n return (blobRef && isPlausibleBlobRef(blobRef)) ? blobRef : null;\n}\n\nfunction blobInfoUpdate(bmap) {\n var blobmeta = document.getElementById('blobmeta');\n var bd = document.getElementById(\"blobdownload\")\n bd.innerHTML = \"\";\n var blobref = getBlobParam();\n if (!blobref) {\n alert(\"no blobref?\");\n return;\n }\n var binfo = bmap[blobref];\n if (!binfo) {\n blobmeta.innerHTML = \"(not found)\";\n return;\n }\n blobmeta.innerHTML = JSON.stringify(binfo, null, 2);\n if (binfo.camliType || (binfo.type && binfo.type.indexOf(\"text/\") == 0)) {\n camliGetBlobContents(\n blobref,\n {\n success: function(data) {\n document.getElementById(\"blobdata\").innerHTML = linkifyBlobRefs(data);\n var bb = document.getElementById('blobbrowse');\n if (binfo.camliType != \"directory\") {\n bb.style.visibility = 'hidden';\n } else {\n bb.innerHTML = \"browse\";\n }\n if (binfo.camliType == \"file\") {\n try {\n finfo = JSON.parse(data);\n bd.innerHTML = \"\";\n var fileName = finfo.fileName || blobref;\n bd.firstChild.href = \"./download/\" + blobref + \"/\" + fileName;\n if (binfo.file.mimeType.indexOf(\"image/\") == 0) {\n document.getElementById(\"thumbnail\").innerHTML = \"\";\n } else {\n document.getElementById(\"thumbnail\").innerHTML = \"\";\n }\n bd.firstChild.innerText = fileName;\n bd.innerHTML = \"download: \" + bd.innerHTML;\n } catch (x) {\n }\n }\n },\n fail: alert\n });\n } else {\n document.getElementById(\"blobdata\").innerHTML = \"Unknown/binary data\";\n }\n bd.innerHTML = \"download\";\n\n if (binfo.camliType && binfo.camliType == \"permanode\") {\n document.getElementById(\"editspan\").style.display = \"inline\";\n document.getElementById(\"editlink\").href = \"./?p=\" + blobref;\n\n var claims = document.getElementById(\"claimsdiv\");\n claims.style.visibility = \"\";\n camliGetPermanodeClaims(\n blobref,\n {\n success: function(data) {\n document.getElementById(\"claims\").innerHTML = linkifyBlobRefs(JSON.stringify(data, null, 2));\n },\n fail: function(msg) {\n alert(msg);\n }\n });\n }\n\n}\n\nfunction blobInfoOnLoad() {\n var blobref = getBlobParam();\n if (!blobref) {\n return\n }\n var blobmeta = document.getElementById('blobmeta');\n blobmeta.innerText = \"(loading)\";\n\n var blobdescribe = document.getElementById('blobdescribe');\n blobdescribe.innerHTML = \"describe\";\n camliDescribeBlob(\n blobref,\n {\n success: blobInfoUpdate,\n fail: function(msg) {\n alert(\"Error describing blob \" + blobref + \": \" + msg);\n }\n }\n );\n}\n\nwindow.addEventListener(\"load\", blobInfoOnLoad);\n", time.Unix(0, 1311540591000000000)); } diff --git a/server/camlistored/ui/zembed_camli.js.go b/server/camlistored/ui/zembed_camli.js.go index f5d9f29d5..4a09b973c 100644 --- a/server/camlistored/ui/zembed_camli.js.go +++ b/server/camlistored/ui/zembed_camli.js.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM camli.js // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("camli.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// Camli namespace.\nvar Camli = {};\n\nvar disco = null; // TODO: kill this in favor of Camli.config.\n\n// Method 1 to get discovery information (JSONP style):\nfunction onConfiguration(config) {\n Camli.config = disco = config;\n console.log(\"Got config: \" + JSON.stringify(config));\n}\n\nfunction saneOpts(opts) {\n if (!opts) {\n opts = {}\n }\n if (!opts.success) {\n opts.success = function() {};\n }\n if (!opts.fail) {\n opts.fail = function() {};\n }\n return opts;\n}\n\n// Format |dateVal| as specified by RFC 3339.\nfunction dateToRfc3339String(dateVal) {\n // Return a string containing |num| zero-padded to |length| digits.\n var pad = function(num, length) {\n var numStr = \"\" + num;\n while (numStr.length < length) {\n numStr = \"0\" + numStr;\n }\n return numStr;\n }\n return dateVal.getUTCFullYear() + \"-\" + pad(dateVal.getUTCMonth() + 1, 2) + \"-\" + pad(dateVal.getUTCDate(), 2) + \"T\" +\n pad(dateVal.getUTCHours(), 2) + \":\" + pad(dateVal.getUTCMinutes(), 2) + \":\" + pad(dateVal.getUTCSeconds(), 2) + \"Z\";\n}\n\nvar cachedCamliSigDiscovery;\n\n// opts.success called with discovery object\n// opts.fail called with error text\nfunction camliSigDiscovery(opts) {\n opts = saneOpts(opts);\n if (cachedCamliSigDiscovery) {\n opts.success(cachedCamliSigDiscovery);\n return;\n }\n var cb = {};\n cb.success = function(sd) {\n cachedCamliSigDiscovery = sd;\n opts.success(sd);\n };\n cb.fail = opts.fail;\n var xhr = camliJsonXhr(\"camliSigDiscovery\", cb);\n xhr.open(\"GET\", Camli.config.jsonSignRoot + \"/camli/sig/discovery\", true);\n xhr.send();\n}\n\nfunction camliDescribeBlob(blobref, opts) {\n var xhr = camliJsonXhr(\"camliDescribeBlob\", opts);\n var path = Camli.config.searchRoot + \"camli/search/describe?blobref=\" +\n blobref;\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\nfunction makeURL(base, map) {\n for (var key in map) {\n if (base.indexOf(\"?\") == -1) {\n base += \"?\";\n } else {\n base += \"&\";\n }\n base += key + \"=\" + encodeURIComponent(map[key]);\n }\n return base;\n}\n\nfunction camliPermanodeOfSignerAttrValue(signer, attr, value, opts) {\n var xhr = camliJsonXhr(\"camliPermanodeOfSignerAttrValue\", opts);\n var path = makeURL(Camli.config.searchRoot + \"camli/search/signerattrvalue\",\n { signer: signer, attr: attr, value: value });\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\n// Where is the target accessed via? (paths it's at)\nfunction camliPathsOfSignerTarget(signer, target, opts) {\n var xhr = camliJsonXhr(\"camliPathsOfSignerTarget\", opts);\n var path = makeURL(Camli.config.searchRoot + \"camli/search/signerpaths\",\n { signer: signer, target: target });\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\nfunction camliGetPermanodeClaims(permanode, opts) {\n var xhr = camliJsonXhr(\"camliGetPermanodeClaims\", opts);\n var path = Camli.config.searchRoot + \"camli/search/claims?permanode=\" +\n permanode;\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\nfunction camliGetBlobContents(blobref, opts) {\n opts = saneOpts(opts);\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n opts.fail(\"camliGetBlobContents HTTP status \" + xhr.status);\n return;\n }\n opts.success(xhr.responseText);\n };\n xhr.open(\"GET\", camliBlobURL(blobref), true);\n xhr.send();\n}\n\nfunction camliBlobURL(blobref) {\n return Camli.config.blobRoot + \"camli/\" + blobref;\n}\n\nfunction camliDescribeBlogURL(blobref) {\n return Camli.config.searchRoot + 'camli/search/describe?blobref=' + blobref;\n}\n\nfunction camliSign(clearObj, opts) {\n opts = saneOpts(opts);\n\n camliSigDiscovery(\n {\n success: function(sigConf) {\n if (!sigConf.publicKeyBlobRef) {\n opts.fail(\"Missing sigConf.publicKeyBlobRef\");\n return;\n }\n clearObj.camliSigner = sigConf.publicKeyBlobRef;\n clearText = JSON.stringify(clearObj, null, 2);\n\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n opts.fail(\"got status \" + xhr.status);\n return;\n }\n opts.success(xhr.responseText);\n };\n xhr.open(\"POST\", sigConf.signHandler, true);\n xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n xhr.send(\"json=\" + encodeURIComponent(clearText));\n },\n fail: function(errMsg) {\n opts.fail(errMsg);\n }\n });\n}\n\n// file: File object\n// contentsBlobRef: blob ref of file as sha1'd locally\n// opts: fail(strMsg) success(strFileBlobRef) of the validated (or uploaded + created) file schema blob.\n// associating with a permanode is caller's job.\nfunction camliUploadFileHelper(file, contentsBlobRef, opts) {\n opts = saneOpts(opts);\n if (!Camli.config.uploadHelper) {\n opts.fail(\"no uploadHelper available\");\n return\n }\n\n var doUpload = function() {\n var fd = new FormData();\n fd.append(fd, file);\n var uploadCb = { fail: opts.fail };\n uploadCb.success = function(res) {\n if (res.got && res.got.length == 1 && res.got[0].fileref) {\n var fileblob = res.got[0].fileref;\n console.log(\"uploaded \" + contentsBlobRef + \" => file blob \" + fileblob);\n opts.success(fileblob);\n } else {\n opts.fail(\"failed to upload \" + file.name + \": \" + contentsBlobRef + \": \" + JSON.stringify(res, null, 2))\n }\n };\n var xhr = camliJsonXhr(\"camliUploadFileHelper\", uploadCb);\n xhr.open(\"POST\", Camli.config.uploadHelper);\n xhr.send(fd);\n };\n\n var dupcheckCb = { fail: opts.fail };\n dupcheckCb.success = function(res) {\n var remain = res.files;\n var checkNext;\n checkNext = function() {\n if (remain.length == 0) {\n doUpload();\n return;\n }\n // TODO: verify filename and other file metadata in the\n // file json schema match too, not just the contents\n var checkFile = remain.shift();\n console.log(\"integrity checking the reported dup \" + checkFile);\n\n var vcb = {};\n vcb.fail = function(xhr) {\n console.log(\"integrity checked failed on \" + checkFile);\n checkNext();\n };\n vcb.success = function(xhr) {\n if (xhr.getResponseHeader(\"X-Camli-Contents\") == contentsBlobRef) {\n console.log(\"integrity checked passed on \" + checkFile + \"; using it.\");\n opts.success(checkFile);\n } else {\n checkNext();\n }\n };\n var xhr = camliXhr(\"headVerifyFile\", vcb);\n xhr.open(\"HEAD\", Camli.config.downloadHelper + checkFile + \"/?verifycontents=\" + contentsBlobRef, true);\n xhr.send();\n };\n checkNext();\n };\n camliFindExistingFileSchemas(contentsBlobRef, dupcheckCb);\n}\n\nfunction camliUploadString(s, opts) {\n opts = saneOpts(opts);\n var blobref = \"sha1-\" + Crypto.SHA1(s);\n\n bb = new WebKitBlobBuilder();\n bb.append(s);\n\n var fd = new FormData();\n fd.append(blobref, bb.getBlob());\n\n var uploadCb = {};\n uploadCb.success = function(resj) {\n // TODO: check resj.received[] array.\n opts.success(blobref);\n };\n uploadCb.fail = opts.fail;\n var xhr = camliJsonXhr(\"camliUploadString\", uploadCb);\n // TODO: hack, hard-coding the upload URL here.\n // Change the spec now that App Engine permits 32 MB requests\n // and permit a PUT request on the sha1? Or at least let us\n // specify the well-known upload URL? In cases like this, uploading\n // a new permanode, it's silly to even stat.\n xhr.open(\"POST\", Camli.config.blobRoot + \"camli/upload\")\n xhr.send(fd);\n}\n\nfunction camliCreateNewPermanode(opts) {\n opts = saneOpts(opts);\n var json = {\n \"camliVersion\": 1,\n \"camliType\": \"permanode\",\n \"random\": \"\"+Math.random()\n };\n camliSign(json, {\n success: function(got) {\n camliUploadString(\n got,\n {\n success: opts.success,\n fail: function(msg) {\n opts.fail(\"upload permanode fail: \" + msg);\n }\n });\n },\n fail: function(msg) {\n opts.fail(\"sign permanode fail: \" + msg);\n }\n });\n}\n\n// Returns the first value from the query string corresponding to |key|.\n// Returns null if the key isn't present.\nfunction getQueryParam(key) {\n var params = document.location.search.substring(1).split('&');\n for (var i = 0; i < params.length; ++i) {\n var parts = params[i].split('=');\n if (parts.length == 2 && decodeURIComponent(parts[0]) == key)\n return decodeURIComponent(parts[1]);\n }\n return null;\n}\n\nfunction camliGetRecentlyUpdatedPermanodes(opts) {\n var xhr = camliJsonXhr(\"camliGetRecentlyUpdatedPermanodes\", opts);\n xhr.open(\"GET\", Camli.config.searchRoot + \"camli/search/recent\", true);\n xhr.send();\n}\n\nfunction camliGetPermanodesWithAttr(signer, attr, value, fuzzy, opts) {\n var xhr = camliJsonXhr(\"camliGetPermanodesWithAttr\", opts);\n var path = makeURL(Camli.config.searchRoot + \"camli/search/permanodeattr\",\n { signer: signer, attr: attr, value: value, fuzzy: fuzzy });\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\nfunction camliXhr(name, opts) {\n opts = saneOpts(opts);\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status == 200) {\n opts.success(xhr);\n } else {\n opts.fail(name + \": expected status 200; got \" + xhr.status + \": \" + xhr.responseText);\n }\n };\n return xhr;\n}\n\nfunction camliJsonXhr(name, opts) {\n opts = saneOpts(opts);\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n try {\n var resj = JSON.parse(xhr.responseText);\n opts.fail(name + \": expected status 200; got \" + xhr.status + \": \" + resj.error);\n } catch(x) {\n opts.fail(name + \": expected status 200; got \" + xhr.status + \": \" + xhr.responseText);\n }\n return;\n }\n var resj;\n try {\n resj = JSON.parse(xhr.responseText);\n } catch(x) {\n opts.fail(name + \": error parsing JSON in response: \" + xhr.responseText);\n return\n }\n if (resj.error) {\n opts.fail(resj.error);\n } else {\n opts.success(resj);\n }\n };\n return xhr;\n}\n\nfunction camliFindExistingFileSchemas(wholeDigestRef, opts) {\n var xhr = camliJsonXhr(\"camliFindExistingFileSchemas\", opts);\n var path = Camli.config.searchRoot + \"camli/search/files?wholedigest=\" +\n wholeDigestRef;\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\n// Returns true if the passed-in string might be a blobref.\nfunction isPlausibleBlobRef(blobRef) {\n return /^\\w+-[a-f0-9]+$/.test(blobRef);\n}\n\nfunction linkifyBlobRefs(schemaBlob) {\n var re = /(\\w{3,6}-[a-f0-9]{30,})/g;\n return schemaBlob.replace(re, \"$1\");\n}\n\n// Helper function for camliNewSetAttributeClaim() (and eventually, for\n// similar functions to add or delete attributes).\nfunction changeAttribute(permanode, claimType, attribute, value, opts) {\n opts = saneOpts(opts);\n var json = {\n \"camliVersion\": 1,\n \"camliType\": \"claim\",\n \"permaNode\": permanode,\n \"claimType\": claimType,\n \"claimDate\": dateToRfc3339String(new Date()),\n \"attribute\": attribute,\n \"value\": value\n };\n camliSign(json, {\n success: function(signedBlob) {\n camliUploadString(signedBlob, {\n success: opts.success,\n fail: function(msg) {\n opts.fail(\"upload \" + claimType + \" fail: \" + msg);\n }\n });\n },\n fail: function(msg) {\n opts.fail(\"sign \" + claimType + \" fail: \" + msg);\n }\n });\n}\n\nfunction camliBlobTitle(pn, des) {\n return _camliBlobTitleOrThumb(pn, des, 0, 0);\n}\n\nfunction camliBlobThumbnail(pn, des, width, height) {\n return _camliBlobTitleOrThumb(pn, des, width, height);\n}\n\n// pn: permanode to find a good title of\n// jdes: describe response of root permanode\n// w, h: if both of them are non-zero, returns html of an wxh size thumbnail, not a title.\nfunction _camliBlobTitleOrThumb(pn, des, w, h) {\n var d = des[pn];\n if (!d) {\n return pn;\n }\n if (d.camliType == \"file\" && d.file && d.file.fileName) {\n var fileName = d.file.fileName\n if (w != 0 && h != 0 && d.file.mimeType && d.file.mimeType.indexOf(\"image/\") == 0) {\n var img = \"\\?&]/g, \"\") + \"?mw=\" + w + \"&mh=\" + h + \"'>\";\n return img;\n }\n return fileName;\n }\n if (d.permanode) {\n var attr = d.permanode.attr;\n if (!attr) {\n return pn;\n }\n if (attr.title) {\n return attr.title[0];\n }\n if (attr.camliContent) {\n return _camliBlobTitleOrThumb(attr.camliContent[0], des, w, h);\n }\n }\n return pn;\n}\n\n// Create and upload a new set-attribute claim.\nfunction camliNewSetAttributeClaim(permanode, attribute, value, opts) {\n changeAttribute(permanode, \"set-attribute\", attribute, value, opts);\n}\n\n// Create and upload a new add-attribute claim.\nfunction camliNewAddAttributeClaim(permanode, attribute, value, opts) {\n changeAttribute(permanode, \"add-attribute\", attribute, value, opts);\n}\n\n// Create and upload a new del-attribute claim.\nfunction camliNewDelAttributeClaim(permanode, attribute, value, opts) {\n changeAttribute(permanode, \"del-attribute\", attribute, value, opts);\n}\n\n"); + Files.Add("camli.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// Camli namespace.\nvar Camli = {};\n\nvar disco = null; // TODO: kill this in favor of Camli.config.\n\n// Method 1 to get discovery information (JSONP style):\nfunction onConfiguration(config) {\n Camli.config = disco = config;\n console.log(\"Got config: \" + JSON.stringify(config));\n}\n\nfunction saneOpts(opts) {\n if (!opts) {\n opts = {}\n }\n if (!opts.success) {\n opts.success = function() {};\n }\n if (!opts.fail) {\n opts.fail = function() {};\n }\n return opts;\n}\n\n// Format |dateVal| as specified by RFC 3339.\nfunction dateToRfc3339String(dateVal) {\n // Return a string containing |num| zero-padded to |length| digits.\n var pad = function(num, length) {\n var numStr = \"\" + num;\n while (numStr.length < length) {\n numStr = \"0\" + numStr;\n }\n return numStr;\n }\n return dateVal.getUTCFullYear() + \"-\" + pad(dateVal.getUTCMonth() + 1, 2) + \"-\" + pad(dateVal.getUTCDate(), 2) + \"T\" +\n pad(dateVal.getUTCHours(), 2) + \":\" + pad(dateVal.getUTCMinutes(), 2) + \":\" + pad(dateVal.getUTCSeconds(), 2) + \"Z\";\n}\n\nvar cachedCamliSigDiscovery;\n\n// opts.success called with discovery object\n// opts.fail called with error text\nfunction camliSigDiscovery(opts) {\n opts = saneOpts(opts);\n if (cachedCamliSigDiscovery) {\n opts.success(cachedCamliSigDiscovery);\n return;\n }\n var cb = {};\n cb.success = function(sd) {\n cachedCamliSigDiscovery = sd;\n opts.success(sd);\n };\n cb.fail = opts.fail;\n var xhr = camliJsonXhr(\"camliSigDiscovery\", cb);\n xhr.open(\"GET\", Camli.config.jsonSignRoot + \"/camli/sig/discovery\", true);\n xhr.send();\n}\n\nfunction camliDescribeBlob(blobref, opts) {\n var xhr = camliJsonXhr(\"camliDescribeBlob\", opts);\n var path = Camli.config.searchRoot + \"camli/search/describe?blobref=\" +\n blobref;\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\nfunction makeURL(base, map) {\n for (var key in map) {\n if (base.indexOf(\"?\") == -1) {\n base += \"?\";\n } else {\n base += \"&\";\n }\n base += key + \"=\" + encodeURIComponent(map[key]);\n }\n return base;\n}\n\nfunction camliPermanodeOfSignerAttrValue(signer, attr, value, opts) {\n var xhr = camliJsonXhr(\"camliPermanodeOfSignerAttrValue\", opts);\n var path = makeURL(Camli.config.searchRoot + \"camli/search/signerattrvalue\",\n { signer: signer, attr: attr, value: value });\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\n// Where is the target accessed via? (paths it's at)\nfunction camliPathsOfSignerTarget(signer, target, opts) {\n var xhr = camliJsonXhr(\"camliPathsOfSignerTarget\", opts);\n var path = makeURL(Camli.config.searchRoot + \"camli/search/signerpaths\",\n { signer: signer, target: target });\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\nfunction camliGetPermanodeClaims(permanode, opts) {\n var xhr = camliJsonXhr(\"camliGetPermanodeClaims\", opts);\n var path = Camli.config.searchRoot + \"camli/search/claims?permanode=\" +\n permanode;\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\nfunction camliGetBlobContents(blobref, opts) {\n opts = saneOpts(opts);\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n opts.fail(\"camliGetBlobContents HTTP status \" + xhr.status);\n return;\n }\n opts.success(xhr.responseText);\n };\n xhr.open(\"GET\", camliBlobURL(blobref), true);\n xhr.send();\n}\n\nfunction camliBlobURL(blobref) {\n return Camli.config.blobRoot + \"camli/\" + blobref;\n}\n\nfunction camliDescribeBlogURL(blobref) {\n return Camli.config.searchRoot + 'camli/search/describe?blobref=' + blobref;\n}\n\nfunction camliSign(clearObj, opts) {\n opts = saneOpts(opts);\n\n camliSigDiscovery(\n {\n success: function(sigConf) {\n if (!sigConf.publicKeyBlobRef) {\n opts.fail(\"Missing sigConf.publicKeyBlobRef\");\n return;\n }\n clearObj.camliSigner = sigConf.publicKeyBlobRef;\n clearText = JSON.stringify(clearObj, null, 2);\n\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n opts.fail(\"got status \" + xhr.status);\n return;\n }\n opts.success(xhr.responseText);\n };\n xhr.open(\"POST\", sigConf.signHandler, true);\n xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n xhr.send(\"json=\" + encodeURIComponent(clearText));\n },\n fail: function(errMsg) {\n opts.fail(errMsg);\n }\n });\n}\n\n// file: File object\n// contentsBlobRef: blob ref of file as sha1'd locally\n// opts: fail(strMsg) success(strFileBlobRef) of the validated (or uploaded + created) file schema blob.\n// associating with a permanode is caller's job.\nfunction camliUploadFileHelper(file, contentsBlobRef, opts) {\n opts = saneOpts(opts);\n if (!Camli.config.uploadHelper) {\n opts.fail(\"no uploadHelper available\");\n return\n }\n\n var doUpload = function() {\n var fd = new FormData();\n fd.append(fd, file);\n var uploadCb = { fail: opts.fail };\n uploadCb.success = function(res) {\n if (res.got && res.got.length == 1 && res.got[0].fileref) {\n var fileblob = res.got[0].fileref;\n console.log(\"uploaded \" + contentsBlobRef + \" => file blob \" + fileblob);\n opts.success(fileblob);\n } else {\n opts.fail(\"failed to upload \" + file.name + \": \" + contentsBlobRef + \": \" + JSON.stringify(res, null, 2))\n }\n };\n var xhr = camliJsonXhr(\"camliUploadFileHelper\", uploadCb);\n xhr.open(\"POST\", Camli.config.uploadHelper);\n xhr.send(fd);\n };\n\n var dupcheckCb = { fail: opts.fail };\n dupcheckCb.success = function(res) {\n var remain = res.files;\n var checkNext;\n checkNext = function() {\n if (remain.length == 0) {\n doUpload();\n return;\n }\n // TODO: verify filename and other file metadata in the\n // file json schema match too, not just the contents\n var checkFile = remain.shift();\n console.log(\"integrity checking the reported dup \" + checkFile);\n\n var vcb = {};\n vcb.fail = function(xhr) {\n console.log(\"integrity checked failed on \" + checkFile);\n checkNext();\n };\n vcb.success = function(xhr) {\n if (xhr.getResponseHeader(\"X-Camli-Contents\") == contentsBlobRef) {\n console.log(\"integrity checked passed on \" + checkFile + \"; using it.\");\n opts.success(checkFile);\n } else {\n checkNext();\n }\n };\n var xhr = camliXhr(\"headVerifyFile\", vcb);\n xhr.open(\"HEAD\", Camli.config.downloadHelper + checkFile + \"/?verifycontents=\" + contentsBlobRef, true);\n xhr.send();\n };\n checkNext();\n };\n camliFindExistingFileSchemas(contentsBlobRef, dupcheckCb);\n}\n\nfunction camliUploadString(s, opts) {\n opts = saneOpts(opts);\n var blobref = \"sha1-\" + Crypto.SHA1(s);\n\n bb = new WebKitBlobBuilder();\n bb.append(s);\n\n var fd = new FormData();\n fd.append(blobref, bb.getBlob());\n\n var uploadCb = {};\n uploadCb.success = function(resj) {\n // TODO: check resj.received[] array.\n opts.success(blobref);\n };\n uploadCb.fail = opts.fail;\n var xhr = camliJsonXhr(\"camliUploadString\", uploadCb);\n // TODO: hack, hard-coding the upload URL here.\n // Change the spec now that App Engine permits 32 MB requests\n // and permit a PUT request on the sha1? Or at least let us\n // specify the well-known upload URL? In cases like this, uploading\n // a new permanode, it's silly to even stat.\n xhr.open(\"POST\", Camli.config.blobRoot + \"camli/upload\")\n xhr.send(fd);\n}\n\nfunction camliCreateNewPermanode(opts) {\n opts = saneOpts(opts);\n var json = {\n \"camliVersion\": 1,\n \"camliType\": \"permanode\",\n \"random\": \"\"+Math.random()\n };\n camliSign(json, {\n success: function(got) {\n camliUploadString(\n got,\n {\n success: opts.success,\n fail: function(msg) {\n opts.fail(\"upload permanode fail: \" + msg);\n }\n });\n },\n fail: function(msg) {\n opts.fail(\"sign permanode fail: \" + msg);\n }\n });\n}\n\n// Returns the first value from the query string corresponding to |key|.\n// Returns null if the key isn't present.\nfunction getQueryParam(key) {\n var params = document.location.search.substring(1).split('&');\n for (var i = 0; i < params.length; ++i) {\n var parts = params[i].split('=');\n if (parts.length == 2 && decodeURIComponent(parts[0]) == key)\n return decodeURIComponent(parts[1]);\n }\n return null;\n}\n\nfunction camliGetRecentlyUpdatedPermanodes(opts) {\n var xhr = camliJsonXhr(\"camliGetRecentlyUpdatedPermanodes\", opts);\n xhr.open(\"GET\", Camli.config.searchRoot + \"camli/search/recent\", true);\n xhr.send();\n}\n\nfunction camliGetPermanodesWithAttr(signer, attr, value, fuzzy, opts) {\n var xhr = camliJsonXhr(\"camliGetPermanodesWithAttr\", opts);\n var path = makeURL(Camli.config.searchRoot + \"camli/search/permanodeattr\",\n { signer: signer, attr: attr, value: value, fuzzy: fuzzy });\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\nfunction camliXhr(name, opts) {\n opts = saneOpts(opts);\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status == 200) {\n opts.success(xhr);\n } else {\n opts.fail(name + \": expected status 200; got \" + xhr.status + \": \" + xhr.responseText);\n }\n };\n return xhr;\n}\n\nfunction camliJsonXhr(name, opts) {\n opts = saneOpts(opts);\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n try {\n var resj = JSON.parse(xhr.responseText);\n opts.fail(name + \": expected status 200; got \" + xhr.status + \": \" + resj.error);\n } catch(x) {\n opts.fail(name + \": expected status 200; got \" + xhr.status + \": \" + xhr.responseText);\n }\n return;\n }\n var resj;\n try {\n resj = JSON.parse(xhr.responseText);\n } catch(x) {\n opts.fail(name + \": error parsing JSON in response: \" + xhr.responseText);\n return\n }\n if (resj.error) {\n opts.fail(resj.error);\n } else {\n opts.success(resj);\n }\n };\n return xhr;\n}\n\nfunction camliFindExistingFileSchemas(wholeDigestRef, opts) {\n var xhr = camliJsonXhr(\"camliFindExistingFileSchemas\", opts);\n var path = Camli.config.searchRoot + \"camli/search/files?wholedigest=\" +\n wholeDigestRef;\n xhr.open(\"GET\", path, true);\n xhr.send();\n}\n\n// Returns true if the passed-in string might be a blobref.\nfunction isPlausibleBlobRef(blobRef) {\n return /^\\w+-[a-f0-9]+$/.test(blobRef);\n}\n\nfunction linkifyBlobRefs(schemaBlob) {\n var re = /(\\w{3,6}-[a-f0-9]{30,})/g;\n return schemaBlob.replace(re, \"$1\");\n}\n\n// Helper function for camliNewSetAttributeClaim() (and eventually, for\n// similar functions to add or delete attributes).\nfunction changeAttribute(permanode, claimType, attribute, value, opts) {\n opts = saneOpts(opts);\n var json = {\n \"camliVersion\": 1,\n \"camliType\": \"claim\",\n \"permaNode\": permanode,\n \"claimType\": claimType,\n \"claimDate\": dateToRfc3339String(new Date()),\n \"attribute\": attribute,\n \"value\": value\n };\n camliSign(json, {\n success: function(signedBlob) {\n camliUploadString(signedBlob, {\n success: opts.success,\n fail: function(msg) {\n opts.fail(\"upload \" + claimType + \" fail: \" + msg);\n }\n });\n },\n fail: function(msg) {\n opts.fail(\"sign \" + claimType + \" fail: \" + msg);\n }\n });\n}\n\nfunction camliBlobTitle(pn, des) {\n return _camliBlobTitleOrThumb(pn, des, 0, 0);\n}\n\nfunction camliBlobThumbnail(pn, des, width, height) {\n return _camliBlobTitleOrThumb(pn, des, width, height);\n}\n\n// pn: permanode to find a good title of\n// jdes: describe response of root permanode\n// w, h: if both of them are non-zero, returns html of an wxh size thumbnail, not a title.\nfunction _camliBlobTitleOrThumb(pn, des, w, h) {\n var d = des[pn];\n if (!d) {\n return pn;\n }\n if (d.camliType == \"file\" && d.file && d.file.fileName) {\n var fileName = d.file.fileName\n if (w != 0 && h != 0 && d.file.mimeType && d.file.mimeType.indexOf(\"image/\") == 0) {\n var img = \"\\?&]/g, \"\") + \"?mw=\" + w + \"&mh=\" + h + \"'>\";\n return img;\n }\n return fileName;\n }\n if (d.permanode) {\n var attr = d.permanode.attr;\n if (!attr) {\n return pn;\n }\n if (attr.title) {\n return attr.title[0];\n }\n if (attr.camliContent) {\n return _camliBlobTitleOrThumb(attr.camliContent[0], des, w, h);\n }\n }\n return pn;\n}\n\n// Create and upload a new set-attribute claim.\nfunction camliNewSetAttributeClaim(permanode, attribute, value, opts) {\n changeAttribute(permanode, \"set-attribute\", attribute, value, opts);\n}\n\n// Create and upload a new add-attribute claim.\nfunction camliNewAddAttributeClaim(permanode, attribute, value, opts) {\n changeAttribute(permanode, \"add-attribute\", attribute, value, opts);\n}\n\n// Create and upload a new del-attribute claim.\nfunction camliNewDelAttributeClaim(permanode, attribute, value, opts) {\n changeAttribute(permanode, \"del-attribute\", attribute, value, opts);\n}\n\n", time.Unix(0, 1316041554000000000)); } diff --git a/server/camlistored/ui/zembed_disco.html.go b/server/camlistored/ui/zembed_disco.html.go index 2998060f0..cc95b1146 100644 --- a/server/camlistored/ui/zembed_disco.html.go +++ b/server/camlistored/ui/zembed_disco.html.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM disco.html // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("disco.html", "\n\n Camlistored UI\n \n \n \n\n\n\n
\n

Root Discovery

\n

\n
(discovery results)
\n\n\n

Signing Discovery

\n

\n
(jsonsign discovery results)
\n
\n\n\n"); + Files.Add("disco.html", "\n\n Camlistored UI\n \n \n \n\n\n\n
\n

Root Discovery

\n

\n
(discovery results)
\n\n\n

Signing Discovery

\n

\n
(jsonsign discovery results)
\n
\n\n\n", time.Unix(0, 1309407835000000000)); } diff --git a/server/camlistored/ui/zembed_filetree.html.go b/server/camlistored/ui/zembed_filetree.html.go index 393213412..cfc3801e6 100644 --- a/server/camlistored/ui/zembed_filetree.html.go +++ b/server/camlistored/ui/zembed_filetree.html.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM filetree.html // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("filetree.html", "\n\n\n Gallery\n \n \n \n \n \n \n \n\n\n
Home
\n

FileTree for

\n\n
\n\n\n\n"); + Files.Add("filetree.html", "\n\n\n Gallery\n \n \n \n \n \n \n \n\n\n
Home
\n

FileTree for

\n\n
\n\n\n\n", time.Unix(0, 1311540591000000000)); } diff --git a/server/camlistored/ui/zembed_filetree.js.go b/server/camlistored/ui/zembed_filetree.js.go index bb38e3ec4..34e9596b8 100644 --- a/server/camlistored/ui/zembed_filetree.js.go +++ b/server/camlistored/ui/zembed_filetree.js.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM filetree.js // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("filetree.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\t http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// CamliFileTree namespace\nvar CamliFileTree = {};\n\n// Gets the |d| query parameter, assuming that it looks like a blobref.\n\nfunction getPermanodeParam() {\n\tvar blobRef = getQueryParam('d');\n\treturn (blobRef && isPlausibleBlobRef(blobRef)) ? blobRef : null;\n}\n\nfunction newPermWithContent(content) {\n\treturn function(e) {\n\t\tvar cnpcb = {};\n\t\tcnpcb.success = function(permanode) {\n\t\t\tvar naaccb = {};\n\t\t\tnaaccb.success = function() {\n\t\t\t\talert(\"permanode created\");\n\t\t\t}\n\t\t\tnaaccb.fail = function(msg) {\n//TODO(mpl): remove newly created permanode then?\n\t\t\t\talert(\"set permanode content failed: \" + msg);\n\t\t\t}\n\t\t\tcamliNewAddAttributeClaim(permanode, \"camliContent\", content, naaccb);\n\t\t}\n\t\tcnpcb.fail = function(msg) {\n\t\t\talert(\"create permanode failed: \" + msg);\n\t\t}\n\t camliCreateNewPermanode(cnpcb);\n\t}\n}\n\nfunction getFileTree(blobref, opts) {\n\tvar xhr = camliJsonXhr(\"getFileTree\", opts);\n\tvar path = \"./tree/\" + blobref\n\txhr.open(\"GET\", path, true);\n\txhr.send();\n}\n\nfunction insertAfter( referenceNode, newNode )\n{\n\t// nextSibling X2 because of the \"P\" span\n\treferenceNode.parentNode.insertBefore( newNode, referenceNode.nextSibling.nextSibling );\n}\n\nfunction unFold(blobref, depth) {\n\tvar node = document.getElementById(blobref);\n\tvar div = document.createElement(\"div\");\n\tvar gftcb = {};\n\tgftcb.success = function(jres) {\n\t\tonChildrenFound(div, depth+1, jres);\n\t\tinsertAfter(node, div)\n\t\tnode.onclick = Function(\"fold('\" + blobref + \"' , \" + depth + \"); return false;\");\n\t}\n\tgftcb.fail = function() { alert(\"fail\"); }\n\tgetFileTree(blobref, gftcb);\n}\n\nfunction fold(nodeid, depth) {\n\tvar node = document.getElementById(nodeid);\n\t// nextSibling X2 because of the \"P\" span\n\tnode.parentNode.removeChild(node.nextSibling.nextSibling);\n\tnode.onclick = Function(\"unFold('\" + nodeid + \"' , \" + depth + \"); return false;\");\n}\n\nfunction onChildrenFound(div, depth, jres) {\n\tvar indent = depth * CamliFileTree.indentStep\n\tdiv.innerHTML = \"\";\n\tfor (var i = 0; i < jres.children.length; i++) {\n\t\tvar children = jres.children;\n\t\tvar pdiv = document.createElement(\"div\");\n\t\tvar alink = document.createElement(\"a\");\n\t\talink.style.paddingLeft=indent + \"px\"\n\t\talink.id = children[i].blobRef;\n\t\tswitch (children[i].type) {\n\t\tcase 'directory':\n\t\t\talink.innerText = \"+ \" + children[i].name;\n\t\t\talink.href = \"./?d=\" + alink.id;\n\t\t\talink.onclick = Function(\"unFold('\" + alink.id + \"', \" + depth + \"); return false;\");\n\t\t\tbreak;\n\t\tcase 'file':\n\t\t\talink.innerText = \" \" + children[i].name;\n\t\t\talink.href = \"./?b=\" + alink.id;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\talert(\"not a file or dir\");\n\t\t\tbreak;\n\t\t}\n\t\tvar newPerm = document.createElement(\"span\");\n\t\tnewPerm.className = \"camli-newp\";\n\t\tnewPerm.innerText = \"P\";\n\t\tnewPerm.addEventListener(\"click\", newPermWithContent(alink.id));\n\t\tpdiv.appendChild(alink);\n\t\tpdiv.appendChild(newPerm);\n\t\tdiv.appendChild(pdiv);\n\t}\n}\n\nfunction buildTree() {\n\tvar blobref = getPermanodeParam();\n\n\tvar div = document.getElementById(\"children\");\n\tvar gftcb = {};\n\tgftcb.success = function(jres) { onChildrenFound(div, 0, jres); }\n\tgftcb.fail = function() { alert(\"fail\"); }\n\tgetFileTree(blobref, gftcb)\n}\n\nfunction treePageOnLoad(e) {\n\tvar blobref = getPermanodeParam();\n\tif (blobref) {\n\t\tvar dbcb = {};\n\t\tdbcb.success = function(bmap) {\n\t\t\tvar binfo = bmap[blobref];\n\t\t\tif (!binfo) {\n\t\t\t\talert(\"Error describing blob \" + blobref);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (binfo.camliType != \"directory\") {\n\t\t\t\talert(\"Does not contain a directory\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar gbccb = {};\n\t\t\tgbccb.success = function(data) {\n\t\t\t\ttry {\n\t\t\t\t\tfinfo = JSON.parse(data);\n\t\t\t\t\tvar fileName = finfo.fileName;\n\t\t\t\t\tvar curDir = document.getElementById('curDir');\n\t\t\t\t\tcurDir.innerHTML = \"\" + fileName + \"\";\n\t\t\t\t\tCamliFileTree.indentStep = 20;\n\t\t\t\t\tbuildTree();\n\t\t\t\t} catch(x) {\n\t\t\t\t\talert(x);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tgbccb.fail = function() {\n\t\t\t\talert(\"failed to get blobcontents\");\n\t\t\t}\n\t\t\tcamliGetBlobContents(blobref, gbccb);\n\t\t}\n\t\tdbcb.fail = function(msg) {\n\t\t\talert(\"Error describing blob \" + blobref + \": \" + msg);\n\t\t}\n\t\tcamliDescribeBlob(blobref, dbcb);\n\t}\n}\n\nwindow.addEventListener(\"load\", treePageOnLoad);\n"); + Files.Add("filetree.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n\t http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// CamliFileTree namespace\nvar CamliFileTree = {};\n\n// Gets the |d| query parameter, assuming that it looks like a blobref.\n\nfunction getPermanodeParam() {\n\tvar blobRef = getQueryParam('d');\n\treturn (blobRef && isPlausibleBlobRef(blobRef)) ? blobRef : null;\n}\n\nfunction newPermWithContent(content) {\n\treturn function(e) {\n\t\tvar cnpcb = {};\n\t\tcnpcb.success = function(permanode) {\n\t\t\tvar naaccb = {};\n\t\t\tnaaccb.success = function() {\n\t\t\t\talert(\"permanode created\");\n\t\t\t}\n\t\t\tnaaccb.fail = function(msg) {\n//TODO(mpl): remove newly created permanode then?\n\t\t\t\talert(\"set permanode content failed: \" + msg);\n\t\t\t}\n\t\t\tcamliNewAddAttributeClaim(permanode, \"camliContent\", content, naaccb);\n\t\t}\n\t\tcnpcb.fail = function(msg) {\n\t\t\talert(\"create permanode failed: \" + msg);\n\t\t}\n\t camliCreateNewPermanode(cnpcb);\n\t}\n}\n\nfunction getFileTree(blobref, opts) {\n\tvar xhr = camliJsonXhr(\"getFileTree\", opts);\n\tvar path = \"./tree/\" + blobref\n\txhr.open(\"GET\", path, true);\n\txhr.send();\n}\n\nfunction insertAfter( referenceNode, newNode )\n{\n\t// nextSibling X2 because of the \"P\" span\n\treferenceNode.parentNode.insertBefore( newNode, referenceNode.nextSibling.nextSibling );\n}\n\nfunction unFold(blobref, depth) {\n\tvar node = document.getElementById(blobref);\n\tvar div = document.createElement(\"div\");\n\tvar gftcb = {};\n\tgftcb.success = function(jres) {\n\t\tonChildrenFound(div, depth+1, jres);\n\t\tinsertAfter(node, div)\n\t\tnode.onclick = Function(\"fold('\" + blobref + \"' , \" + depth + \"); return false;\");\n\t}\n\tgftcb.fail = function() { alert(\"fail\"); }\n\tgetFileTree(blobref, gftcb);\n}\n\nfunction fold(nodeid, depth) {\n\tvar node = document.getElementById(nodeid);\n\t// nextSibling X2 because of the \"P\" span\n\tnode.parentNode.removeChild(node.nextSibling.nextSibling);\n\tnode.onclick = Function(\"unFold('\" + nodeid + \"' , \" + depth + \"); return false;\");\n}\n\nfunction onChildrenFound(div, depth, jres) {\n\tvar indent = depth * CamliFileTree.indentStep\n\tdiv.innerHTML = \"\";\n\tfor (var i = 0; i < jres.children.length; i++) {\n\t\tvar children = jres.children;\n\t\tvar pdiv = document.createElement(\"div\");\n\t\tvar alink = document.createElement(\"a\");\n\t\talink.style.paddingLeft=indent + \"px\"\n\t\talink.id = children[i].blobRef;\n\t\tswitch (children[i].type) {\n\t\tcase 'directory':\n\t\t\talink.innerText = \"+ \" + children[i].name;\n\t\t\talink.href = \"./?d=\" + alink.id;\n\t\t\talink.onclick = Function(\"unFold('\" + alink.id + \"', \" + depth + \"); return false;\");\n\t\t\tbreak;\n\t\tcase 'file':\n\t\t\talink.innerText = \" \" + children[i].name;\n\t\t\talink.href = \"./?b=\" + alink.id;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\talert(\"not a file or dir\");\n\t\t\tbreak;\n\t\t}\n\t\tvar newPerm = document.createElement(\"span\");\n\t\tnewPerm.className = \"camli-newp\";\n\t\tnewPerm.innerText = \"P\";\n\t\tnewPerm.addEventListener(\"click\", newPermWithContent(alink.id));\n\t\tpdiv.appendChild(alink);\n\t\tpdiv.appendChild(newPerm);\n\t\tdiv.appendChild(pdiv);\n\t}\n}\n\nfunction buildTree() {\n\tvar blobref = getPermanodeParam();\n\n\tvar div = document.getElementById(\"children\");\n\tvar gftcb = {};\n\tgftcb.success = function(jres) { onChildrenFound(div, 0, jres); }\n\tgftcb.fail = function() { alert(\"fail\"); }\n\tgetFileTree(blobref, gftcb)\n}\n\nfunction treePageOnLoad(e) {\n\tvar blobref = getPermanodeParam();\n\tif (blobref) {\n\t\tvar dbcb = {};\n\t\tdbcb.success = function(bmap) {\n\t\t\tvar binfo = bmap[blobref];\n\t\t\tif (!binfo) {\n\t\t\t\talert(\"Error describing blob \" + blobref);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (binfo.camliType != \"directory\") {\n\t\t\t\talert(\"Does not contain a directory\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar gbccb = {};\n\t\t\tgbccb.success = function(data) {\n\t\t\t\ttry {\n\t\t\t\t\tfinfo = JSON.parse(data);\n\t\t\t\t\tvar fileName = finfo.fileName;\n\t\t\t\t\tvar curDir = document.getElementById('curDir');\n\t\t\t\t\tcurDir.innerHTML = \"\" + fileName + \"\";\n\t\t\t\t\tCamliFileTree.indentStep = 20;\n\t\t\t\t\tbuildTree();\n\t\t\t\t} catch(x) {\n\t\t\t\t\talert(x);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tgbccb.fail = function() {\n\t\t\t\talert(\"failed to get blobcontents\");\n\t\t\t}\n\t\t\tcamliGetBlobContents(blobref, gbccb);\n\t\t}\n\t\tdbcb.fail = function(msg) {\n\t\t\talert(\"Error describing blob \" + blobref + \": \" + msg);\n\t\t}\n\t\tcamliDescribeBlob(blobref, dbcb);\n\t}\n}\n\nwindow.addEventListener(\"load\", treePageOnLoad);\n", time.Unix(0, 1311540591000000000)); } diff --git a/server/camlistored/ui/zembed_gallery.html.go b/server/camlistored/ui/zembed_gallery.html.go index 81d315ccf..dd2f53e82 100644 --- a/server/camlistored/ui/zembed_gallery.html.go +++ b/server/camlistored/ui/zembed_gallery.html.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM gallery.html // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("gallery.html", "\n\n\n Gallery\n \n \n \n \n \n \n \n\n\n
Home
\n

Gallery

\n\n

\n Permalink:\n \n \n

\n\n
\n\n\n\n"); + Files.Add("gallery.html", "\n\n\n Gallery\n \n \n \n \n \n \n \n\n\n
Home
\n

Gallery

\n\n

\n Permalink:\n \n \n

\n\n
\n\n\n\n", time.Unix(0, 1309849899000000000)); } diff --git a/server/camlistored/ui/zembed_gallery.js.go b/server/camlistored/ui/zembed_gallery.js.go index d2b81be96..65b7c342b 100644 --- a/server/camlistored/ui/zembed_gallery.js.go +++ b/server/camlistored/ui/zembed_gallery.js.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM gallery.js // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("gallery.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// Gets the |g| query parameter, assuming that it looks like a blobref.\n\nfunction getPermanodeParam() {\n var blobRef = getQueryParam('g');\n return (blobRef && isPlausibleBlobRef(blobRef)) ? blobRef : null;\n}\n\n// pn: child permanode\n// des: describe response of root permanode\nfunction addMember(pn, des) {\n var membersDiv = document.getElementById(\"members\");\n var ul;\n if (membersDiv.innerHTML == \"\") {\n membersDiv.appendChild(document.createTextNode(\"Members:\"));\n ul = document.createElement(\"ul\");\n membersDiv.appendChild(ul);\n } else {\n ul = membersDiv.firstChild.nextSibling;\n }\n var li = document.createElement(\"li\");\n var a = document.createElement(\"a\");\n a.href = \"./?p=\" + pn;\n a.innerHTML = camliBlobThumbnail(pn, des, 100, 100);\n\n li.appendChild(a);\n ul.appendChild(li);\n}\n\nfunction onMemberDescribed(bmap, jres, member) {\n\taddMember(member, jres)\n}\n\nfunction onBlobDescribed(jres) {\n var permanode = getPermanodeParam();\n if (!jres[permanode]) {\n alert(\"didn't get blob \" + permanode);\n return;\n }\n var permanodeObject = jres[permanode].permanode;\n if (!permanodeObject) {\n alert(\"blob \" + permanode + \" isn't a permanode\");\n return;\n }\n\n document.getElementById('members').innerHTML = '';\n var members = permanodeObject.attr.camliMember;\n if (members && members.length > 0) {\n for (idx in members) {\n var member = members[idx];\n camliDescribeBlob(\n member,\n {\n success: addMember(member, jres),\n fail: function(msg) {\n alert(\"Error describing blob \" + blobref + \": \" + msg);\n }\n }\n ); \n \n }\n }\n}\n\nfunction buildGallery() {\n camliDescribeBlob(getPermanodeParam(), {\n success: onBlobDescribed,\n failure: function(msg) {\n alert(\"failed to get blob description: \" + msg);\n }\n });\n}\n\nfunction galleryPageOnLoad(e) {\n var permanode = getPermanodeParam();\n if (permanode) {\n document.getElementById('permanode').innerHTML = \"\" + permanode + \"\";\n document.getElementById('permanodeBlob').innerHTML = \"view blob\";\n }\n\n buildGallery();\n}\n\nwindow.addEventListener(\"load\", galleryPageOnLoad);\n"); + Files.Add("gallery.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// Gets the |g| query parameter, assuming that it looks like a blobref.\n\nfunction getPermanodeParam() {\n var blobRef = getQueryParam('g');\n return (blobRef && isPlausibleBlobRef(blobRef)) ? blobRef : null;\n}\n\n// pn: child permanode\n// des: describe response of root permanode\nfunction addMember(pn, des) {\n var membersDiv = document.getElementById(\"members\");\n var ul;\n if (membersDiv.innerHTML == \"\") {\n membersDiv.appendChild(document.createTextNode(\"Members:\"));\n ul = document.createElement(\"ul\");\n membersDiv.appendChild(ul);\n } else {\n ul = membersDiv.firstChild.nextSibling;\n }\n var li = document.createElement(\"li\");\n var a = document.createElement(\"a\");\n a.href = \"./?p=\" + pn;\n a.innerHTML = camliBlobThumbnail(pn, des, 100, 100);\n\n li.appendChild(a);\n ul.appendChild(li);\n}\n\nfunction onMemberDescribed(bmap, jres, member) {\n\taddMember(member, jres)\n}\n\nfunction onBlobDescribed(jres) {\n var permanode = getPermanodeParam();\n if (!jres[permanode]) {\n alert(\"didn't get blob \" + permanode);\n return;\n }\n var permanodeObject = jres[permanode].permanode;\n if (!permanodeObject) {\n alert(\"blob \" + permanode + \" isn't a permanode\");\n return;\n }\n\n document.getElementById('members').innerHTML = '';\n var members = permanodeObject.attr.camliMember;\n if (members && members.length > 0) {\n for (idx in members) {\n var member = members[idx];\n camliDescribeBlob(\n member,\n {\n success: addMember(member, jres),\n fail: function(msg) {\n alert(\"Error describing blob \" + blobref + \": \" + msg);\n }\n }\n ); \n \n }\n }\n}\n\nfunction buildGallery() {\n camliDescribeBlob(getPermanodeParam(), {\n success: onBlobDescribed,\n failure: function(msg) {\n alert(\"failed to get blob description: \" + msg);\n }\n });\n}\n\nfunction galleryPageOnLoad(e) {\n var permanode = getPermanodeParam();\n if (permanode) {\n document.getElementById('permanode').innerHTML = \"\" + permanode + \"\";\n document.getElementById('permanodeBlob').innerHTML = \"view blob\";\n }\n\n buildGallery();\n}\n\nwindow.addEventListener(\"load\", galleryPageOnLoad);\n", time.Unix(0, 1309849899000000000)); } diff --git a/server/camlistored/ui/zembed_home.html.go b/server/camlistored/ui/zembed_home.html.go index 0ba819309..33f82a549 100644 --- a/server/camlistored/ui/zembed_home.html.go +++ b/server/camlistored/ui/zembed_home.html.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM home.html // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("home.html", "\n\n Camlistored UI\n \n \n \n \n \n \n \n\n\n

Camlistored UI

\n

Debug:\n discovery |\n signing

\n\n - create a new item or collection \n\n

Recent Objects

\n \n\n

Search

\n
\n

\n \n \n

\n\n

Upload

\n
\n \n \n \n \n
\n\n\n\n"); + Files.Add("home.html", "\n\n Camlistored UI\n \n \n \n \n \n \n \n\n\n

Camlistored UI

\n

Debug:\n discovery |\n signing

\n\n - create a new item or collection \n\n

Recent Objects

\n \n\n

Search

\n
\n

\n \n \n

\n\n

Upload

\n
\n \n \n \n \n
\n\n\n\n", time.Unix(0, 1312665089000000000)); } diff --git a/server/camlistored/ui/zembed_home.js.go b/server/camlistored/ui/zembed_home.js.go index ee5e5e74b..19eee1cb0 100644 --- a/server/camlistored/ui/zembed_home.js.go +++ b/server/camlistored/ui/zembed_home.js.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM home.js // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("home.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// CamliHome namespace to contain the global vars\nvar CamliHome = {};\n\nfunction btnCreateNewPermanode(e) {\n camliCreateNewPermanode(\n {\n success: function(blobref) {\n window.location = \"./?p=\" + blobref;\n },\n fail: function(msg) {\n alert(\"create permanode failed: \" + msg);\n }\n });\n}\n\nfunction handleFormSearch(e) {\n e.stopPropagation();\n e.preventDefault();\n\n var input = document.getElementById(\"inputSearch\");\n var btn = document.getElementById(\"btnSearch\");\n\n if (input.value == \"\") {\n return;\n }\n\n var query = input.value.split(/\\s*,\\s*/);\n window.location = \"./search.html?q=\" + query[0] + \"&t=tag\";\n}\n\nfunction indexOnLoad(e) {\n var btnNew = document.getElementById(\"btnNew\");\n if (!btnNew) {\n alert(\"missing btnNew\");\n }\n btnNew.addEventListener(\"click\", btnCreateNewPermanode);\n camliGetRecentlyUpdatedPermanodes({ success: indexBuildRecentlyUpdatedPermanodes });\n formSearch.addEventListener(\"submit\", handleFormSearch);\n\n if (disco && disco.uploadHelper) {\n var uploadForm = document.getElementById(\"uploadform\");\n uploadform.action = disco.uploadHelper;\n document.getElementById(\"fileinput\").disabled = false;\n document.getElementById(\"filesubmit\").disabled = false;\n var chkRollSum = document.getElementById(\"chkrollsum\");\n chkRollSum.addEventListener(\"change\", function (e) {\n if (chkRollSum.checked) {\n if (disco.uploadHelper.indexOf(\"?\") == -1) {\n uploadform.action = disco.uploadHelper + \"?rollsum=1\";\n } else {\n uploadform.action = disco.uploadHelper + \"&rollsum=1\";\n }\n } else {\n uploadform.action = disco.uploadHelper;\n }\n });\n }\n}\n\nfunction indexBuildRecentlyUpdatedPermanodes(searchRes) {\n var div = document.getElementById(\"recent\");\n div.innerHTML = \"\";\n for (var i = 0; i < searchRes.recent.length; i++) {\n var result = searchRes.recent[i]; \n var pdiv = document.createElement(\"li\");\n var alink = document.createElement(\"a\");\n alink.href = \"./?p=\" + result.blobref;\n alink.innerText = camliBlobTitle(result.blobref, searchRes);\n pdiv.appendChild(alink);\n div.appendChild(pdiv);\n }\n}\n\nwindow.addEventListener(\"load\", indexOnLoad);\n"); + Files.Add("home.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// CamliHome namespace to contain the global vars\nvar CamliHome = {};\n\nfunction btnCreateNewPermanode(e) {\n camliCreateNewPermanode(\n {\n success: function(blobref) {\n window.location = \"./?p=\" + blobref;\n },\n fail: function(msg) {\n alert(\"create permanode failed: \" + msg);\n }\n });\n}\n\nfunction handleFormSearch(e) {\n e.stopPropagation();\n e.preventDefault();\n\n var input = document.getElementById(\"inputSearch\");\n var btn = document.getElementById(\"btnSearch\");\n\n if (input.value == \"\") {\n return;\n }\n\n var query = input.value.split(/\\s*,\\s*/);\n window.location = \"./search.html?q=\" + query[0] + \"&t=tag\";\n}\n\nfunction indexOnLoad(e) {\n var btnNew = document.getElementById(\"btnNew\");\n if (!btnNew) {\n alert(\"missing btnNew\");\n }\n btnNew.addEventListener(\"click\", btnCreateNewPermanode);\n camliGetRecentlyUpdatedPermanodes({ success: indexBuildRecentlyUpdatedPermanodes });\n formSearch.addEventListener(\"submit\", handleFormSearch);\n\n if (disco && disco.uploadHelper) {\n var uploadForm = document.getElementById(\"uploadform\");\n uploadform.action = disco.uploadHelper;\n document.getElementById(\"fileinput\").disabled = false;\n document.getElementById(\"filesubmit\").disabled = false;\n var chkRollSum = document.getElementById(\"chkrollsum\");\n chkRollSum.addEventListener(\"change\", function (e) {\n if (chkRollSum.checked) {\n if (disco.uploadHelper.indexOf(\"?\") == -1) {\n uploadform.action = disco.uploadHelper + \"?rollsum=1\";\n } else {\n uploadform.action = disco.uploadHelper + \"&rollsum=1\";\n }\n } else {\n uploadform.action = disco.uploadHelper;\n }\n });\n }\n}\n\nfunction indexBuildRecentlyUpdatedPermanodes(searchRes) {\n var div = document.getElementById(\"recent\");\n div.innerHTML = \"\";\n for (var i = 0; i < searchRes.recent.length; i++) {\n var result = searchRes.recent[i]; \n var pdiv = document.createElement(\"li\");\n var alink = document.createElement(\"a\");\n alink.href = \"./?p=\" + result.blobref;\n alink.innerText = camliBlobTitle(result.blobref, searchRes);\n pdiv.appendChild(alink);\n div.appendChild(pdiv);\n }\n}\n\nwindow.addEventListener(\"load\", indexOnLoad);\n", time.Unix(0, 1323566533000000000)); } diff --git a/server/camlistored/ui/zembed_permanode.html.go b/server/camlistored/ui/zembed_permanode.html.go index 0d67a4b93..0ad5dbdf8 100644 --- a/server/camlistored/ui/zembed_permanode.html.go +++ b/server/camlistored/ui/zembed_permanode.html.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM permanode.html // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("permanode.html", "\n\n\n Permanode\n \n \n \n \n \n \n \n\n\n
Home
\n

Permanode

\n\n

\n Permalink:\n \n \n

\n\n
\n

\n Title: \n \n

\n
\n\n
\n

\n \n \n \n \n

\n\n
\n

Access:\n \n \n\n ... with URL: \n \n \n

\n
\n\n
\n\n
\n\n
\n

Type:\n \n

\n
\n\n

\n \n

\n\n
\n\n
\n
\n \n \n
\n

\n or drag & drop files here\n

\n
\n  
\n\n

Current object attributes

\n
\n\n\n\n");
+	Files.Add("permanode.html", "\n\n\n  Permanode\n  \n  \n  \n  \n  \n  \n  \n\n\n  
Home
\n

Permanode

\n\n

\n Permalink:\n \n \n

\n\n
\n

\n Title: \n \n

\n
\n\n
\n

\n \n \n \n \n

\n\n
\n

Access:\n \n \n\n ... with URL: \n \n \n

\n
\n\n
\n\n
\n\n
\n

Type:\n \n

\n
\n\n

\n \n

\n\n
\n\n
\n
\n \n \n
\n

\n or drag & drop files here\n

\n
\n  
\n\n

Current object attributes

\n
\n\n\n\n", time.Unix(0, 1309849899000000000));
 }
diff --git a/server/camlistored/ui/zembed_permanode.js.go b/server/camlistored/ui/zembed_permanode.js.go
index 5c72e6807..4aa442acb 100644
--- a/server/camlistored/ui/zembed_permanode.js.go
+++ b/server/camlistored/ui/zembed_permanode.js.go
@@ -1,6 +1,7 @@
 // THIS FILE IS AUTO-GENERATED FROM permanode.js
 // DO NOT EDIT.
 package ui
+import "time"
 func init() {
-	Files.Add("permanode.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// Gets the |p| query parameter, assuming that it looks like a blobref.\n\nfunction getPermanodeParam() {\n    var blobRef = getQueryParam('p');\n    return (blobRef && isPlausibleBlobRef(blobRef)) ? blobRef : null;\n}\n\nfunction handleFormTitleSubmit(e) {\n    e.stopPropagation();\n    e.preventDefault();\n\n    var inputTitle = document.getElementById(\"inputTitle\");\n    inputTitle.disabled = true;\n    var btnSaveTitle = document.getElementById(\"btnSaveTitle\");\n    btnSaveTitle.disabled = true;\n\n    var startTime = new Date();\n\n    camliNewSetAttributeClaim(\n        getPermanodeParam(),\n        \"title\",\n        inputTitle.value,\n        {\n            success: function() {\n                var elapsedMs = new Date().getTime() - startTime.getTime();\n                setTimeout(function() {\n                    inputTitle.disabled = false;\n                    btnSaveTitle.disabled = false;\n                    buildPermanodeUi();\n                }, Math.max(250 - elapsedMs, 0));\n            },\n            fail: function(msg) {\n                alert(msg);\n                inputTitle.disabled = false;\n                btnSaveTitle.disabled = false;\n            }\n        });\n}\n\nfunction handleFormTagsSubmit(e) {\n    e.stopPropagation();\n    e.preventDefault();\n\n    var input = document.getElementById(\"inputNewTag\");\n    var btn = document.getElementById(\"btnAddTag\");\n\n    if (input.value == \"\") {\n        return;\n    }\n\n    input.disabled = true;\n    btn.disabled = true;\n\n    var startTime = new Date();\n\n    var tags = input.value.split(/\\s*,\\s*/);\n    var nRemain = tags.length;\n\n    var oneDone = function() {\n        nRemain--;\n        if (nRemain == 0) {\n            var elapsedMs = new Date().getTime() - startTime.getTime();\n            setTimeout(function() {\n                           input.value = '';\n                           input.disabled = false;\n                           btn.disabled = false;\n                           buildPermanodeUi();\n                       }, Math.max(250 - elapsedMs, 0));\n        }\n    };\n    for (idx in tags) {\n        var tag = tags[idx];\n        camliNewAddAttributeClaim(\n            getPermanodeParam(),\n            \"tag\",\n            tag,\n            {\n                success: oneDone,\n                fail: function(msg) {\n                    alert(msg);\n                    oneDone();\n                }\n            });\n    }\n}\n\nfunction handleFormAccessSubmit(e) {\n    e.stopPropagation();\n    e.preventDefault();\n\n    var selectAccess = document.getElementById(\"selectAccess\");\n    selectAccess.disabled = true;\n    var btnSaveAccess = document.getElementById(\"btnSaveAccess\");\n    btnSaveAccess.disabled = true;\n\n    var operation = camliNewDelAttributeClaim;\n    var value = \"\";\n    if (selectAccess.value != \"private\") {\n        operation = camliNewSetAttributeClaim;\n        value = selectAccess.value;\n    }\n\n    var startTime = new Date();\n\n    operation(\n        getPermanodeParam(),\n        \"camliAccess\",\n        value,\n        {\n            success: function() {\n                var elapsedMs = new Date().getTime() - startTime.getTime();\n                setTimeout(function() {\n                    selectAccess.disabled = false;\n                    btnSaveAccess.disabled = false;\n                }, Math.max(250 - elapsedMs, 0));\n            },\n            fail: function(msg) {\n                alert(msg);\n                selectAccess.disabled = false;\n                btnSaveAccess.disabled = false;\n            }\n        });\n}\n\nfunction deleteTagFunc(tag, strikeEle, removeEle) {\n    return function(e) {\n        strikeEle.innerHTML = \"\" + strikeEle.innerHTML + \"\";\n        camliNewDelAttributeClaim(\n            getPermanodeParam(),\n            \"tag\",\n            tag,\n            {\n                success: function() {\n                    removeEle.parentNode.removeChild(removeEle);\n                },\n                fail: function(msg) {\n                    alert(msg);\n                }\n            });\n    };\n}\n\nfunction onTypeChange() {\n    var sel = document.getElementById(\"type\");\n    var dnd = document.getElementById(\"dnd\");\n    var btnGallery = document.getElementById(\"btnGallery\");\n\n    if (sel.value == \"collection\" || sel.value == \"\") {\n        dnd.style.display = \"block\";\n        btnGallery.style.visibility = 'visible';\n    } else {\n        dnd.style.display = \"none\";\n        btnGallery.style.visibility = 'hidden';\n    }\n}\n\nvar lastFiles;\nfunction handleFiles(files) {\n    lastFiles = files;\n\n    for (var i = 0; i < files.length; i++) {\n        var file = files[i];\n        startFileUpload(file);\n    }\n}\n\nfunction startFileUpload(file) {\n    var dnd = document.getElementById(\"dnd\");\n    var up = document.createElement(\"div\");\n    up.className= 'camli-dnd-item';\n    dnd.appendChild(up);\n    var info = \"name=\" + file.name + \" size=\" + file.size + \"; type=\" + file.type;\n\n    var setStatus = function(status) {\n        up.innerHTML = info + \" \" + status;\n    };\n    setStatus(\"(scanning)\");\n\n    var contentsRef; // set later\n\n    var onFail = function(msg) {\n        up.innerHTML = info + \" fail: \";\n        up.appendChild(document.createTextNode(msg));\n    };\n\n    var onGotFileSchemaRef = function(fileref) {\n        setStatus(\" fileref: \" + fileref + \"\");\n        camliCreateNewPermanode(\n            {\n            success: function(filepn) {\n                var doneWithAll = function() {\n                    setStatus(\"- done\");\n                    buildPermanodeUi();\n                };\n                var addMemberToParent = function() {\n                    setStatus(\"adding member\");\n                    camliNewAddAttributeClaim(getPermanodeParam(), \"camliMember\", filepn, { success: doneWithAll, fail: onFail });\n                };\n                var makePermanode = function() {\n                    setStatus(\"making permanode\");\n                    camliNewSetAttributeClaim(filepn, \"camliContent\", fileref, { success: addMemberToParent, fail: onFail });\n                };\n                makePermanode();\n            },\n            fail: onFail\n        });\n    };\n\n    var fr = new FileReader();\n    fr.onload = function() {\n        dataurl = fr.result;\n        comma = dataurl.indexOf(\",\");\n        if (comma != -1) {\n            b64 = dataurl.substring(comma + 1);\n            var arrayBuffer = Base64.decode(b64).buffer;\n            var hash = Crypto.SHA1(new Uint8Array(arrayBuffer, 0));\n\n            contentsRef = \"sha1-\" + hash;\n            setStatus(\"(checking for dup of \" + contentsRef + \")\");\n            camliUploadFileHelper(file, contentsRef, {\n              success: onGotFileSchemaRef, fail: onFail\n            });\n        }\n    };\n    fr.onerror = function() {\n        console.log(\"FileReader onerror: \" + fr.error + \" code=\" + fr.error.code);\n    };\n    fr.readAsDataURL(file);\n}\n\nfunction onFileFormSubmit(e) {\n    e.stopPropagation();\n    e.preventDefault();\n    alert(\"TODO: upload\");\n}\n\nfunction onFileInputChange(e) {\n    handleFiles(document.getElementById(\"fileInput\").files);\n}\n\nfunction setupFilesHandlers(e) {\n    var dnd = document.getElementById(\"dnd\");\n    document.getElementById(\"fileForm\").addEventListener(\"submit\", onFileFormSubmit);\n    document.getElementById(\"fileInput\").addEventListener(\"change\", onFileInputChange);\n\n    var stop = function(e) {\n        this.classList && this.classList.add('camli-dnd-over');\n        e.stopPropagation();\n        e.preventDefault();\n    };\n    dnd.addEventListener(\"dragenter\", stop, false);\n    dnd.addEventListener(\"dragover\", stop, false);\n\n\n    dnd.addEventListener(\"dragleave\", function() {\n            this.classList.remove('camli-dnd-over');\n        }, false);\n\n    var drop = function(e) {\n        this.classList.remove('camli-dnd-over');\n        stop(e);\n        var dt = e.dataTransfer;\n        var files = dt.files;\n        document.getElementById(\"info\").innerHTML = \"\";\n        handleFiles(files);\n    };\n    dnd.addEventListener(\"drop\", drop, false);\n}\n\n\n// member: child permanode\nfunction deleteMember(member, strikeEle, removeEle) {\n  return function(e) {\n        strikeEle.innerHTML = \"\" + strikeEle.innerHTML + \"\";\n        camliNewDelAttributeClaim(\n            getPermanodeParam(),\n            \"camliMember\",\n            member,\n            {\n                success: function() {\n                    removeEle.parentNode.removeChild(removeEle);\n                },\n                fail: function(msg) {\n                    alert(msg);\n                }\n            });\n    };\n}\n\n// pn: child permanode\n// des: describe response of root permanode\nfunction addMember(pn, des) {\n    var membersDiv = document.getElementById(\"members\");\n    var ul;\n    if (membersDiv.innerHTML == \"\") {\n        membersDiv.appendChild(document.createTextNode(\"Members:\"));\n        ul = document.createElement(\"ul\");\n        membersDiv.appendChild(ul);\n    } else {\n        ul = membersDiv.firstChild.nextSibling;\n    }\n    var li = document.createElement(\"li\");\n    var a = document.createElement(\"a\");\n    a.href = \"./?p=\" + pn;\n    a.innerText = camliBlobTitle(pn, des);\n\n    var del = document.createElement(\"span\");\n    del.className = 'camli-del';\n    del.innerText = \"x\";\n    del.addEventListener(\"click\", deleteMember(pn, a, li));\n\n    li.appendChild(a);\n    li.appendChild(del);\n    ul.appendChild(li);\n}\n\nfunction buildPermanodeUi() {\n    camliDescribeBlob(getPermanodeParam(), {\n        success: onBlobDescribed,\n        failure: function(msg) {\n            alert(\"failed to get blob description: \" + msg);\n        }\n    });\n}\n\nfunction onBlobDescribed(jres) {\n    var permanode = getPermanodeParam();\n    if (!jres[permanode]) {\n        alert(\"didn't get blob \" + permanode);\n        return;\n    }\n    var permanodeObject = jres[permanode].permanode;\n    if (!permanodeObject) {\n        alert(\"blob \" + permanode + \" isn't a permanode\");\n        return;\n    }\n\n    document.getElementById(\"debugattrs\").innerText = JSON.stringify(permanodeObject.attr, null, 2);\n\n    var attr = function(name) {\n        if (!(name in permanodeObject.attr)) {\n            return null;          \n        }\n        if (permanodeObject.attr[name].length == 0) {\n            return null;\n        }\n        return permanodeObject.attr[name][0];\n    };\n\n    var disablePublish = false;\n\n    var selType = document.getElementById(\"type\");\n    if (attr(\"camliRoot\")) {\n        selType.value = \"root\";\n        disablePublish = true;  // can't give a URL to a root with a claim\n    } else if (attr(\"camliContent\")) {\n        selType.value = \"file\";\n    } else if (attr(\"camliMember\")) {\n        selType.value = \"collection\";\n    }\n    onTypeChange();\n\n    document.getElementById(\"selectPublishRoot\").disabled = disablePublish;\n    document.getElementById(\"publishSuffix\").disabled = disablePublish;\n    document.getElementById(\"btnSavePublish\").disabled = disablePublish;\n\n    var inputTitle = document.getElementById(\"inputTitle\");\n    inputTitle.value = attr(\"title\") ? attr(\"title\") : \"\";\n    inputTitle.disabled = false;\n\n    var spanTags = document.getElementById(\"spanTags\");\n    while (spanTags.firstChild) {\n        spanTags.removeChild(spanTags.firstChild);\n    }\n\n    document.getElementById('members').innerHTML = '';\n    var members = permanodeObject.attr.camliMember;\n    if (members && members.length > 0) {\n        for (idx in members) {\n            var member = members[idx];\n            addMember(member, jres);\n        }\n    }\n\n    var camliContent = permanodeObject.attr.camliContent;\n    if (camliContent && camliContent.length > 0) {\n        camliContent = camliContent[camliContent.length-1];\n        var c = document.getElementById(\"content\");\n        c.innerHTML = \"\";\n        c.appendChild(document.createTextNode(\"File: \"));\n        var a = document.createElement(\"a\");\n        a.href = \"./?b=\" + camliContent;\n        a.innerText = camliBlobTitle(camliContent, jres);\n        c.appendChild(a);\n    }\n\n    var tags = permanodeObject.attr.tag;\n    for (idx in tags) {\n        var tag = tags[idx];\n\n        var tagSpan = document.createElement(\"span\");\n        tagSpan.className = 'camli-tag-c';\n        var tagTextEl = document.createElement(\"span\");\n        tagTextEl.className = 'camli-tag-text';\n        tagTextEl.innerText = tag;\n        tagSpan.appendChild(tagTextEl);\n\n        var tagDel = document.createElement(\"span\");\n        tagDel.className = 'camli-del';\n        tagDel.innerText = \"x\";\n        tagDel.addEventListener(\"click\", deleteTagFunc(tag, tagTextEl, tagSpan));\n\n        tagSpan.appendChild(tagDel);\n        spanTags.appendChild(tagSpan);\n    }\n\n    var selectAccess = document.getElementById(\"selectAccess\");\n    var access = permanodeObject.attr.camliAccess;\n    selectAccess.value = (access && access.length) ? access[0] : \"private\";\n    selectAccess.disabled = false;\n\n    var btnSaveTitle = document.getElementById(\"btnSaveTitle\");\n    btnSaveTitle.disabled = false;\n\n    var btnSaveAccess = document.getElementById(\"btnSaveAccess\");\n    btnSaveAccess.disabled = false;\n}\n\nfunction setupRootsDropdown() {\n    var selRoots = document.getElementById(\"selectPublishRoot\");\n    if (!Camli.config.publishRoots) {\n        console.log(\"no publish roots\");\n        return;\n    }\n    for (var rootName in Camli.config.publishRoots) {\n        var opt = document.createElement(\"option\");\n        opt.setAttribute(\"value\", rootName);\n        opt.appendChild(document.createTextNode(Camli.config.publishRoots[rootName].prefix[0]));\n        selRoots.appendChild(opt);\n    }\n    document.getElementById(\"btnSavePublish\").addEventListener(\"click\", onBtnSavePublish);\n}\n\nfunction onBtnSavePublish(e) {\n    var selRoots = document.getElementById(\"selectPublishRoot\");\n    var suffix = document.getElementById(\"publishSuffix\");\n\n    var ourPermanode = getPermanodeParam();\n    if (!ourPermanode) {\n        return;\n    }\n\n    var publishRoot = selRoots.value;\n    if (!publishRoot) {\n        alert(\"no publish root selected\");\n        return;\n    } \n    var pathSuffix = suffix.value;\n    if (!pathSuffix) {\n        alert(\"no path suffix specified\");\n        return;\n    }\n\n    selRoots.disabled = true;\n    suffix.disabled = true;\n\n    var enabled = function() {\n        selRoots.disabled = false;\n        suffix.disabled = false;\n    };\n\n    // Step 1: resolve selRoots.value -> blobref of the root's permanode.\n    // Step 2: set attribute on the root's permanode, or a sub-permanode\n    // if multiple path components in suffix:\n    //         \"camliPath:\" => permanode-of-ourselves\n\n    var sigcb = {};\n    sigcb.success = function(sigconf) {\n        var savcb = {};\n        savcb.success = function(pnres) {\n            if (!pnres.permanode) {\n                alert(\"failed to publish root's permanode\");\n                enabled();\n                return;\n            }\n            var attrcb = {};\n            attrcb.success = function() {\n                console.log(\"success.\");\n                enabled();\n                selRoots.value = \"\";\n                suffix.value = \"\";\n                buildPathsList();\n            };\n            attrcb.fail = function() {\n                alert(\"failed to set attribute\");\n                enabled();\n            };\n            camliNewSetAttributeClaim(pnres.permanode, \"camliPath:\" + pathSuffix, ourPermanode, attrcb);\n        };\n        savcb.fail = function() {\n            alert(\"failed to find publish root's permanode\");\n            enabled();\n        };\n        camliPermanodeOfSignerAttrValue(sigconf.publicKeyBlobRef, \"camliRoot\", publishRoot, savcb);\n    };\n    sigcb.fail = function() {\n        alert(\"sig disco failed\");\n        enabled();\n    }\n    camliSigDiscovery(sigcb);\n}\n\nfunction buildPathsList() {\n    var ourPermanode = getPermanodeParam();\n    if (!ourPermanode) {\n        return;\n    }\n    var sigcb = {};\n    sigcb.success = function(sigconf) {\n        var findpathcb = {};\n        findpathcb.success = function(jres) {\n            var div = document.getElementById(\"existingPaths\");\n\n            // TODO: there can be multiple paths in this list, but the HTML\n            // UI only shows one.  The UI should show all, and when adding a new one\n            // prompt users whether they want to add to or replace the existing one.\n            // For now we just update the UI to show one.\n            // alert(JSON.stringify(jres, null, 2));\n            if (jres.paths && jres.paths.length > 0) {\n                div.innerHTML = \"Existing paths for this permanode:\";\n                var ul = document.createElement(\"ul\");\n                div.appendChild(ul);\n                for (var idx in jres.paths) {\n                    var path = jres.paths[idx];\n                    var li = document.createElement(\"li\");\n                    var span = document.createElement(\"span\");\n                    li.appendChild(span);\n\n                    var blobLink = document.createElement(\"a\");\n                    blobLink.href = \".?p=\" + path.baseRef;\n                    blobLink.innerText = path.baseRef;\n                    span.appendChild(blobLink);\n\n                    span.appendChild(document.createTextNode(\" - \"));\n\n                    var pathLink = document.createElement(\"a\");\n                    pathLink.href = \"\";\n                    pathLink.innerText = path.suffix;\n                    for (var key in Camli.config.publishRoots) {\n                        var root = Camli.config.publishRoots[key];\n                        if (root.currentPermanode == path.baseRef) {\n                            // Prefix should include a trailing slash.\n                            pathLink.href = root.prefix[0] + path.suffix;\n                            // TODO: Check if we're the latest permanode\n                            // for this path and display some \"old\" notice\n                            // if not.\n                            break;\n                        }\n                    }\n                    span.appendChild(pathLink);\n\n                    var del = document.createElement(\"span\");\n                    del.className = \"camli-del\";\n                    del.innerText = \"x\";\n                    del.addEventListener(\"click\", deletePathFunc(path.baseRef, path.suffix, span));\n                    span.appendChild(del);\n\n                    ul.appendChild(li);\n                }\n            } else {\n                div.innerHTML = \"\";\n            }\n        };\n        camliPathsOfSignerTarget(sigconf.publicKeyBlobRef, ourPermanode, findpathcb);\n    };\n    sigcb.fail = function() {\n        alert(\"sig disco failed\");\n    }\n    camliSigDiscovery(sigcb);\n}\n\nfunction deletePathFunc(sourcePermanode, path, strikeEle) {\n    return function(e) {\n        strikeEle.innerHTML = \"\" + strikeEle.innerHTML + \"\";\n        camliNewDelAttributeClaim(\n            sourcePermanode,\n            \"camliPath:\" + path,\n            getPermanodeParam(),\n            {\n                success: function() {\n                    buildPathsList();\n                },\n                fail: function(msg) {\n                    alert(msg);\n                }\n            });\n    };\n}\n\nfunction btnGoToGallery(e) {\n    var permanode = getPermanodeParam();\n    if (permanode) {\n\t\twindow.open('./?g=' + permanode, 'Gallery')\n\t}\n}\n\nfunction permanodePageOnLoad(e) {\n    var permanode = getPermanodeParam();\n    if (permanode) {\n        document.getElementById('permanode').innerHTML = \"\" + permanode + \"\";\n        document.getElementById('permanodeBlob').innerHTML = \"view blob\";\n    }\n\n    var formTitle = document.getElementById(\"formTitle\");\n    formTitle.addEventListener(\"submit\", handleFormTitleSubmit);\n    var formTags = document.getElementById(\"formTags\");\n    formTags.addEventListener(\"submit\", handleFormTagsSubmit);\n    var formAccess = document.getElementById(\"formAccess\");\n    formAccess.addEventListener(\"submit\", handleFormAccessSubmit);\n\n    var selectType = document.getElementById(\"type\");\n    selectType.addEventListener(\"change\", onTypeChange);\n    var btnGallery = document.getElementById(\"btnGallery\");\n    btnGallery.addEventListener(\"click\", btnGoToGallery);\n\n    setupRootsDropdown();\n    setupFilesHandlers();\n\n    buildPermanodeUi();\n    buildPathsList();\n}\n\nwindow.addEventListener(\"load\", permanodePageOnLoad);\n");
+	Files.Add("permanode.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\n// Gets the |p| query parameter, assuming that it looks like a blobref.\n\nfunction getPermanodeParam() {\n    var blobRef = getQueryParam('p');\n    return (blobRef && isPlausibleBlobRef(blobRef)) ? blobRef : null;\n}\n\nfunction handleFormTitleSubmit(e) {\n    e.stopPropagation();\n    e.preventDefault();\n\n    var inputTitle = document.getElementById(\"inputTitle\");\n    inputTitle.disabled = true;\n    var btnSaveTitle = document.getElementById(\"btnSaveTitle\");\n    btnSaveTitle.disabled = true;\n\n    var startTime = new Date();\n\n    camliNewSetAttributeClaim(\n        getPermanodeParam(),\n        \"title\",\n        inputTitle.value,\n        {\n            success: function() {\n                var elapsedMs = new Date().getTime() - startTime.getTime();\n                setTimeout(function() {\n                    inputTitle.disabled = false;\n                    btnSaveTitle.disabled = false;\n                    buildPermanodeUi();\n                }, Math.max(250 - elapsedMs, 0));\n            },\n            fail: function(msg) {\n                alert(msg);\n                inputTitle.disabled = false;\n                btnSaveTitle.disabled = false;\n            }\n        });\n}\n\nfunction handleFormTagsSubmit(e) {\n    e.stopPropagation();\n    e.preventDefault();\n\n    var input = document.getElementById(\"inputNewTag\");\n    var btn = document.getElementById(\"btnAddTag\");\n\n    if (input.value == \"\") {\n        return;\n    }\n\n    input.disabled = true;\n    btn.disabled = true;\n\n    var startTime = new Date();\n\n    var tags = input.value.split(/\\s*,\\s*/);\n    var nRemain = tags.length;\n\n    var oneDone = function() {\n        nRemain--;\n        if (nRemain == 0) {\n            var elapsedMs = new Date().getTime() - startTime.getTime();\n            setTimeout(function() {\n                           input.value = '';\n                           input.disabled = false;\n                           btn.disabled = false;\n                           buildPermanodeUi();\n                       }, Math.max(250 - elapsedMs, 0));\n        }\n    };\n    for (idx in tags) {\n        var tag = tags[idx];\n        camliNewAddAttributeClaim(\n            getPermanodeParam(),\n            \"tag\",\n            tag,\n            {\n                success: oneDone,\n                fail: function(msg) {\n                    alert(msg);\n                    oneDone();\n                }\n            });\n    }\n}\n\nfunction handleFormAccessSubmit(e) {\n    e.stopPropagation();\n    e.preventDefault();\n\n    var selectAccess = document.getElementById(\"selectAccess\");\n    selectAccess.disabled = true;\n    var btnSaveAccess = document.getElementById(\"btnSaveAccess\");\n    btnSaveAccess.disabled = true;\n\n    var operation = camliNewDelAttributeClaim;\n    var value = \"\";\n    if (selectAccess.value != \"private\") {\n        operation = camliNewSetAttributeClaim;\n        value = selectAccess.value;\n    }\n\n    var startTime = new Date();\n\n    operation(\n        getPermanodeParam(),\n        \"camliAccess\",\n        value,\n        {\n            success: function() {\n                var elapsedMs = new Date().getTime() - startTime.getTime();\n                setTimeout(function() {\n                    selectAccess.disabled = false;\n                    btnSaveAccess.disabled = false;\n                }, Math.max(250 - elapsedMs, 0));\n            },\n            fail: function(msg) {\n                alert(msg);\n                selectAccess.disabled = false;\n                btnSaveAccess.disabled = false;\n            }\n        });\n}\n\nfunction deleteTagFunc(tag, strikeEle, removeEle) {\n    return function(e) {\n        strikeEle.innerHTML = \"\" + strikeEle.innerHTML + \"\";\n        camliNewDelAttributeClaim(\n            getPermanodeParam(),\n            \"tag\",\n            tag,\n            {\n                success: function() {\n                    removeEle.parentNode.removeChild(removeEle);\n                },\n                fail: function(msg) {\n                    alert(msg);\n                }\n            });\n    };\n}\n\nfunction onTypeChange() {\n    var sel = document.getElementById(\"type\");\n    var dnd = document.getElementById(\"dnd\");\n    var btnGallery = document.getElementById(\"btnGallery\");\n\n    if (sel.value == \"collection\" || sel.value == \"\") {\n        dnd.style.display = \"block\";\n        btnGallery.style.visibility = 'visible';\n    } else {\n        dnd.style.display = \"none\";\n        btnGallery.style.visibility = 'hidden';\n    }\n}\n\nvar lastFiles;\nfunction handleFiles(files) {\n    lastFiles = files;\n\n    for (var i = 0; i < files.length; i++) {\n        var file = files[i];\n        startFileUpload(file);\n    }\n}\n\nfunction startFileUpload(file) {\n    var dnd = document.getElementById(\"dnd\");\n    var up = document.createElement(\"div\");\n    up.className= 'camli-dnd-item';\n    dnd.appendChild(up);\n    var info = \"name=\" + file.name + \" size=\" + file.size + \"; type=\" + file.type;\n\n    var setStatus = function(status) {\n        up.innerHTML = info + \" \" + status;\n    };\n    setStatus(\"(scanning)\");\n\n    var contentsRef; // set later\n\n    var onFail = function(msg) {\n        up.innerHTML = info + \" fail: \";\n        up.appendChild(document.createTextNode(msg));\n    };\n\n    var onGotFileSchemaRef = function(fileref) {\n        setStatus(\" fileref: \" + fileref + \"\");\n        camliCreateNewPermanode(\n            {\n            success: function(filepn) {\n                var doneWithAll = function() {\n                    setStatus(\"- done\");\n                    buildPermanodeUi();\n                };\n                var addMemberToParent = function() {\n                    setStatus(\"adding member\");\n                    camliNewAddAttributeClaim(getPermanodeParam(), \"camliMember\", filepn, { success: doneWithAll, fail: onFail });\n                };\n                var makePermanode = function() {\n                    setStatus(\"making permanode\");\n                    camliNewSetAttributeClaim(filepn, \"camliContent\", fileref, { success: addMemberToParent, fail: onFail });\n                };\n                makePermanode();\n            },\n            fail: onFail\n        });\n    };\n\n    var fr = new FileReader();\n    fr.onload = function() {\n        dataurl = fr.result;\n        comma = dataurl.indexOf(\",\");\n        if (comma != -1) {\n            b64 = dataurl.substring(comma + 1);\n            var arrayBuffer = Base64.decode(b64).buffer;\n            var hash = Crypto.SHA1(new Uint8Array(arrayBuffer, 0));\n\n            contentsRef = \"sha1-\" + hash;\n            setStatus(\"(checking for dup of \" + contentsRef + \")\");\n            camliUploadFileHelper(file, contentsRef, {\n              success: onGotFileSchemaRef, fail: onFail\n            });\n        }\n    };\n    fr.onerror = function() {\n        console.log(\"FileReader onerror: \" + fr.error + \" code=\" + fr.error.code);\n    };\n    fr.readAsDataURL(file);\n}\n\nfunction onFileFormSubmit(e) {\n    e.stopPropagation();\n    e.preventDefault();\n    alert(\"TODO: upload\");\n}\n\nfunction onFileInputChange(e) {\n    handleFiles(document.getElementById(\"fileInput\").files);\n}\n\nfunction setupFilesHandlers(e) {\n    var dnd = document.getElementById(\"dnd\");\n    document.getElementById(\"fileForm\").addEventListener(\"submit\", onFileFormSubmit);\n    document.getElementById(\"fileInput\").addEventListener(\"change\", onFileInputChange);\n\n    var stop = function(e) {\n        this.classList && this.classList.add('camli-dnd-over');\n        e.stopPropagation();\n        e.preventDefault();\n    };\n    dnd.addEventListener(\"dragenter\", stop, false);\n    dnd.addEventListener(\"dragover\", stop, false);\n\n\n    dnd.addEventListener(\"dragleave\", function() {\n            this.classList.remove('camli-dnd-over');\n        }, false);\n\n    var drop = function(e) {\n        this.classList.remove('camli-dnd-over');\n        stop(e);\n        var dt = e.dataTransfer;\n        var files = dt.files;\n        document.getElementById(\"info\").innerHTML = \"\";\n        handleFiles(files);\n    };\n    dnd.addEventListener(\"drop\", drop, false);\n}\n\n\n// member: child permanode\nfunction deleteMember(member, strikeEle, removeEle) {\n  return function(e) {\n        strikeEle.innerHTML = \"\" + strikeEle.innerHTML + \"\";\n        camliNewDelAttributeClaim(\n            getPermanodeParam(),\n            \"camliMember\",\n            member,\n            {\n                success: function() {\n                    removeEle.parentNode.removeChild(removeEle);\n                },\n                fail: function(msg) {\n                    alert(msg);\n                }\n            });\n    };\n}\n\n// pn: child permanode\n// des: describe response of root permanode\nfunction addMember(pn, des) {\n    var membersDiv = document.getElementById(\"members\");\n    var ul;\n    if (membersDiv.innerHTML == \"\") {\n        membersDiv.appendChild(document.createTextNode(\"Members:\"));\n        ul = document.createElement(\"ul\");\n        membersDiv.appendChild(ul);\n    } else {\n        ul = membersDiv.firstChild.nextSibling;\n    }\n    var li = document.createElement(\"li\");\n    var a = document.createElement(\"a\");\n    a.href = \"./?p=\" + pn;\n    a.innerText = camliBlobTitle(pn, des);\n\n    var del = document.createElement(\"span\");\n    del.className = 'camli-del';\n    del.innerText = \"x\";\n    del.addEventListener(\"click\", deleteMember(pn, a, li));\n\n    li.appendChild(a);\n    li.appendChild(del);\n    ul.appendChild(li);\n}\n\nfunction buildPermanodeUi() {\n    camliDescribeBlob(getPermanodeParam(), {\n        success: onBlobDescribed,\n        failure: function(msg) {\n            alert(\"failed to get blob description: \" + msg);\n        }\n    });\n}\n\nfunction onBlobDescribed(jres) {\n    var permanode = getPermanodeParam();\n    if (!jres[permanode]) {\n        alert(\"didn't get blob \" + permanode);\n        return;\n    }\n    var permanodeObject = jres[permanode].permanode;\n    if (!permanodeObject) {\n        alert(\"blob \" + permanode + \" isn't a permanode\");\n        return;\n    }\n\n    document.getElementById(\"debugattrs\").innerText = JSON.stringify(permanodeObject.attr, null, 2);\n\n    var attr = function(name) {\n        if (!(name in permanodeObject.attr)) {\n            return null;          \n        }\n        if (permanodeObject.attr[name].length == 0) {\n            return null;\n        }\n        return permanodeObject.attr[name][0];\n    };\n\n    var disablePublish = false;\n\n    var selType = document.getElementById(\"type\");\n    if (attr(\"camliRoot\")) {\n        selType.value = \"root\";\n        disablePublish = true;  // can't give a URL to a root with a claim\n    } else if (attr(\"camliContent\")) {\n        selType.value = \"file\";\n    } else if (attr(\"camliMember\")) {\n        selType.value = \"collection\";\n    }\n    onTypeChange();\n\n    document.getElementById(\"selectPublishRoot\").disabled = disablePublish;\n    document.getElementById(\"publishSuffix\").disabled = disablePublish;\n    document.getElementById(\"btnSavePublish\").disabled = disablePublish;\n\n    var inputTitle = document.getElementById(\"inputTitle\");\n    inputTitle.value = attr(\"title\") ? attr(\"title\") : \"\";\n    inputTitle.disabled = false;\n\n    var spanTags = document.getElementById(\"spanTags\");\n    while (spanTags.firstChild) {\n        spanTags.removeChild(spanTags.firstChild);\n    }\n\n    document.getElementById('members').innerHTML = '';\n    var members = permanodeObject.attr.camliMember;\n    if (members && members.length > 0) {\n        for (idx in members) {\n            var member = members[idx];\n            addMember(member, jres);\n        }\n    }\n\n    var camliContent = permanodeObject.attr.camliContent;\n    if (camliContent && camliContent.length > 0) {\n        camliContent = camliContent[camliContent.length-1];\n        var c = document.getElementById(\"content\");\n        c.innerHTML = \"\";\n        c.appendChild(document.createTextNode(\"File: \"));\n        var a = document.createElement(\"a\");\n        a.href = \"./?b=\" + camliContent;\n        a.innerText = camliBlobTitle(camliContent, jres);\n        c.appendChild(a);\n    }\n\n    var tags = permanodeObject.attr.tag;\n    for (idx in tags) {\n        var tag = tags[idx];\n\n        var tagSpan = document.createElement(\"span\");\n        tagSpan.className = 'camli-tag-c';\n        var tagTextEl = document.createElement(\"span\");\n        tagTextEl.className = 'camli-tag-text';\n        tagTextEl.innerText = tag;\n        tagSpan.appendChild(tagTextEl);\n\n        var tagDel = document.createElement(\"span\");\n        tagDel.className = 'camli-del';\n        tagDel.innerText = \"x\";\n        tagDel.addEventListener(\"click\", deleteTagFunc(tag, tagTextEl, tagSpan));\n\n        tagSpan.appendChild(tagDel);\n        spanTags.appendChild(tagSpan);\n    }\n\n    var selectAccess = document.getElementById(\"selectAccess\");\n    var access = permanodeObject.attr.camliAccess;\n    selectAccess.value = (access && access.length) ? access[0] : \"private\";\n    selectAccess.disabled = false;\n\n    var btnSaveTitle = document.getElementById(\"btnSaveTitle\");\n    btnSaveTitle.disabled = false;\n\n    var btnSaveAccess = document.getElementById(\"btnSaveAccess\");\n    btnSaveAccess.disabled = false;\n}\n\nfunction setupRootsDropdown() {\n    var selRoots = document.getElementById(\"selectPublishRoot\");\n    if (!Camli.config.publishRoots) {\n        console.log(\"no publish roots\");\n        return;\n    }\n    for (var rootName in Camli.config.publishRoots) {\n        var opt = document.createElement(\"option\");\n        opt.setAttribute(\"value\", rootName);\n        opt.appendChild(document.createTextNode(Camli.config.publishRoots[rootName].prefix[0]));\n        selRoots.appendChild(opt);\n    }\n    document.getElementById(\"btnSavePublish\").addEventListener(\"click\", onBtnSavePublish);\n}\n\nfunction onBtnSavePublish(e) {\n    var selRoots = document.getElementById(\"selectPublishRoot\");\n    var suffix = document.getElementById(\"publishSuffix\");\n\n    var ourPermanode = getPermanodeParam();\n    if (!ourPermanode) {\n        return;\n    }\n\n    var publishRoot = selRoots.value;\n    if (!publishRoot) {\n        alert(\"no publish root selected\");\n        return;\n    } \n    var pathSuffix = suffix.value;\n    if (!pathSuffix) {\n        alert(\"no path suffix specified\");\n        return;\n    }\n\n    selRoots.disabled = true;\n    suffix.disabled = true;\n\n    var enabled = function() {\n        selRoots.disabled = false;\n        suffix.disabled = false;\n    };\n\n    // Step 1: resolve selRoots.value -> blobref of the root's permanode.\n    // Step 2: set attribute on the root's permanode, or a sub-permanode\n    // if multiple path components in suffix:\n    //         \"camliPath:\" => permanode-of-ourselves\n\n    var sigcb = {};\n    sigcb.success = function(sigconf) {\n        var savcb = {};\n        savcb.success = function(pnres) {\n            if (!pnres.permanode) {\n                alert(\"failed to publish root's permanode\");\n                enabled();\n                return;\n            }\n            var attrcb = {};\n            attrcb.success = function() {\n                console.log(\"success.\");\n                enabled();\n                selRoots.value = \"\";\n                suffix.value = \"\";\n                buildPathsList();\n            };\n            attrcb.fail = function() {\n                alert(\"failed to set attribute\");\n                enabled();\n            };\n            camliNewSetAttributeClaim(pnres.permanode, \"camliPath:\" + pathSuffix, ourPermanode, attrcb);\n        };\n        savcb.fail = function() {\n            alert(\"failed to find publish root's permanode\");\n            enabled();\n        };\n        camliPermanodeOfSignerAttrValue(sigconf.publicKeyBlobRef, \"camliRoot\", publishRoot, savcb);\n    };\n    sigcb.fail = function() {\n        alert(\"sig disco failed\");\n        enabled();\n    }\n    camliSigDiscovery(sigcb);\n}\n\nfunction buildPathsList() {\n    var ourPermanode = getPermanodeParam();\n    if (!ourPermanode) {\n        return;\n    }\n    var sigcb = {};\n    sigcb.success = function(sigconf) {\n        var findpathcb = {};\n        findpathcb.success = function(jres) {\n            var div = document.getElementById(\"existingPaths\");\n\n            // TODO: there can be multiple paths in this list, but the HTML\n            // UI only shows one.  The UI should show all, and when adding a new one\n            // prompt users whether they want to add to or replace the existing one.\n            // For now we just update the UI to show one.\n            // alert(JSON.stringify(jres, null, 2));\n            if (jres.paths && jres.paths.length > 0) {\n                div.innerHTML = \"Existing paths for this permanode:\";\n                var ul = document.createElement(\"ul\");\n                div.appendChild(ul);\n                for (var idx in jres.paths) {\n                    var path = jres.paths[idx];\n                    var li = document.createElement(\"li\");\n                    var span = document.createElement(\"span\");\n                    li.appendChild(span);\n\n                    var blobLink = document.createElement(\"a\");\n                    blobLink.href = \".?p=\" + path.baseRef;\n                    blobLink.innerText = path.baseRef;\n                    span.appendChild(blobLink);\n\n                    span.appendChild(document.createTextNode(\" - \"));\n\n                    var pathLink = document.createElement(\"a\");\n                    pathLink.href = \"\";\n                    pathLink.innerText = path.suffix;\n                    for (var key in Camli.config.publishRoots) {\n                        var root = Camli.config.publishRoots[key];\n                        if (root.currentPermanode == path.baseRef) {\n                            // Prefix should include a trailing slash.\n                            pathLink.href = root.prefix[0] + path.suffix;\n                            // TODO: Check if we're the latest permanode\n                            // for this path and display some \"old\" notice\n                            // if not.\n                            break;\n                        }\n                    }\n                    span.appendChild(pathLink);\n\n                    var del = document.createElement(\"span\");\n                    del.className = \"camli-del\";\n                    del.innerText = \"x\";\n                    del.addEventListener(\"click\", deletePathFunc(path.baseRef, path.suffix, span));\n                    span.appendChild(del);\n\n                    ul.appendChild(li);\n                }\n            } else {\n                div.innerHTML = \"\";\n            }\n        };\n        camliPathsOfSignerTarget(sigconf.publicKeyBlobRef, ourPermanode, findpathcb);\n    };\n    sigcb.fail = function() {\n        alert(\"sig disco failed\");\n    }\n    camliSigDiscovery(sigcb);\n}\n\nfunction deletePathFunc(sourcePermanode, path, strikeEle) {\n    return function(e) {\n        strikeEle.innerHTML = \"\" + strikeEle.innerHTML + \"\";\n        camliNewDelAttributeClaim(\n            sourcePermanode,\n            \"camliPath:\" + path,\n            getPermanodeParam(),\n            {\n                success: function() {\n                    buildPathsList();\n                },\n                fail: function(msg) {\n                    alert(msg);\n                }\n            });\n    };\n}\n\nfunction btnGoToGallery(e) {\n    var permanode = getPermanodeParam();\n    if (permanode) {\n\t\twindow.open('./?g=' + permanode, 'Gallery')\n\t}\n}\n\nfunction permanodePageOnLoad(e) {\n    var permanode = getPermanodeParam();\n    if (permanode) {\n        document.getElementById('permanode').innerHTML = \"\" + permanode + \"\";\n        document.getElementById('permanodeBlob').innerHTML = \"view blob\";\n    }\n\n    var formTitle = document.getElementById(\"formTitle\");\n    formTitle.addEventListener(\"submit\", handleFormTitleSubmit);\n    var formTags = document.getElementById(\"formTags\");\n    formTags.addEventListener(\"submit\", handleFormTagsSubmit);\n    var formAccess = document.getElementById(\"formAccess\");\n    formAccess.addEventListener(\"submit\", handleFormAccessSubmit);\n\n    var selectType = document.getElementById(\"type\");\n    selectType.addEventListener(\"change\", onTypeChange);\n    var btnGallery = document.getElementById(\"btnGallery\");\n    btnGallery.addEventListener(\"click\", btnGoToGallery);\n\n    setupRootsDropdown();\n    setupFilesHandlers();\n\n    buildPermanodeUi();\n    buildPathsList();\n}\n\nwindow.addEventListener(\"load\", permanodePageOnLoad);\n", time.Unix(0, 1316041554000000000));
 }
diff --git a/server/camlistored/ui/zembed_pics.js.go b/server/camlistored/ui/zembed_pics.js.go
index a4ad11d62..4eba2d85f 100644
--- a/server/camlistored/ui/zembed_pics.js.go
+++ b/server/camlistored/ui/zembed_pics.js.go
@@ -1,6 +1,7 @@
 // THIS FILE IS AUTO-GENERATED FROM pics.js
 // DO NOT EDIT.
 package ui
+import "time"
 func init() {
-	Files.Add("pics.js", "\n// jquery-colorbox browsable photo gallery\n\nfunction addColorboxen() {\n  $(document).ready(function() {\n    $('li > a').each(function() {\n      this.setAttribute('rel', 'camligroup');\n    })\n    $('a[rel=\"camligroup\"]').colorbox({\n      transition:'none',\n      width: '75%',\n      height: '75%',\n      top: '30px',\n      open: false,\n      href: function() {\n        return $(this).parent().find('.camlifile a').attr('href');\n      },\n      title: function() {\n        return $($(this).parent().find('a').get(0)).text();\n      }\n    });\n  });\n}\n\nvar titleInput, editLink;\nfunction init() {\n  $(document).ready(function() {\n    // Before the images are loaded, rewrite the urls to include the square\n    // parameter.\n    $('li img').each(function() {\n      this.src = this.src + '&square=1';\n    });\n\n    if (camliViewIsOwner) {\n      $('body').addClass('camliadmin');\n\n      editLink = $(document.createElement('a'));\n      editLink.attr('#');\n      editLink.addClass('pics-edit');\n      editLink.html('edit title');\n      editLink.click(function(e) {\n        editTitle();\n        e.stopPropagation();\n        e.preventDefault();\n      });\n\n      titleInput = $(document.createElement('input'));\n      titleInput.blur(function() {\n        saveImgTitle($(this));\n      });\n      titleInput.bind('keypress', function(e) {\n        if (e.keyCode == 13) {\n          saveImgTitle($(this));\n        }\n      });\n\n      $('li').mouseenter(function(e) {\n        $(this).find('img').after(editLink);\n        editLink.show();\n      });\n      $('li').mouseleave(function(e) {\n        editLink.hide();\n      });\n    }\n  });\n}\n\nfunction editTitle() {\n  var titleSpan = editLink.next();\n  titleInput.val(titleSpan.text());\n  titleSpan.parent().after(titleInput);\n  titleInput.show();\n  titleInput.focus();\n  titleInput.select();\n  titleSpan.hide();\n  editLink.hide();\n}\n\nfunction saveImgTitle(titleInput) {\n  var spanTitle = titleInput.parent().find('a span');\n  var spanText = spanTitle.text();\n  var newVal = titleInput.val();\n  if (spanText != newVal) {\n    spanTitle.text(newVal);\n    var blobRef = titleInput.parent().attr('id').replace(/^camli-/, '');\n    camliNewSetAttributeClaim(\n      blobRef,\n      \"title\",\n      newVal,\n      {\n          success: function() {\n              titleInput.hide();\n              spanTitle.show();\n              spanTitle.effect('highlight', {}, 300);\n          },\n          fail: function(msg) {\n              alert(msg);\n          }\n      });\n  }\n  titleInput.hide();\n  spanTitle.show();\n}\n\n// Installs jQuery and the colorbox library along with an onload listener\n// to fire the init function above.\nif (typeof window['jQuery'] == 'undefined') {\n  document.write('');\n  document.write('');\n  document.write('');\n  document.write('');\n}\n");
+	Files.Add("pics.js", "\n// jquery-colorbox browsable photo gallery\n\nfunction addColorboxen() {\n  $(document).ready(function() {\n    $('li > a').each(function() {\n      this.setAttribute('rel', 'camligroup');\n    })\n    $('a[rel=\"camligroup\"]').colorbox({\n      transition:'none',\n      width: '75%',\n      height: '75%',\n      top: '30px',\n      open: false,\n      href: function() {\n        return $(this).parent().find('.camlifile a').attr('href');\n      },\n      title: function() {\n        return $($(this).parent().find('a').get(0)).text();\n      }\n    });\n  });\n}\n\nvar titleInput, editLink;\nfunction init() {\n  $(document).ready(function() {\n    // Before the images are loaded, rewrite the urls to include the square\n    // parameter.\n    $('li img').each(function() {\n      this.src = this.src + '&square=1';\n    });\n\n    if (camliViewIsOwner) {\n      $('body').addClass('camliadmin');\n\n      editLink = $(document.createElement('a'));\n      editLink.attr('#');\n      editLink.addClass('pics-edit');\n      editLink.html('edit title');\n      editLink.click(function(e) {\n        editTitle();\n        e.stopPropagation();\n        e.preventDefault();\n      });\n\n      titleInput = $(document.createElement('input'));\n      titleInput.blur(function() {\n        saveImgTitle($(this));\n      });\n      titleInput.bind('keypress', function(e) {\n        if (e.keyCode == 13) {\n          saveImgTitle($(this));\n        }\n      });\n\n      $('li').mouseenter(function(e) {\n        $(this).find('img').after(editLink);\n        editLink.show();\n      });\n      $('li').mouseleave(function(e) {\n        editLink.hide();\n      });\n    }\n  });\n}\n\nfunction editTitle() {\n  var titleSpan = editLink.next();\n  titleInput.val(titleSpan.text());\n  titleSpan.parent().after(titleInput);\n  titleInput.show();\n  titleInput.focus();\n  titleInput.select();\n  titleSpan.hide();\n  editLink.hide();\n}\n\nfunction saveImgTitle(titleInput) {\n  var spanTitle = titleInput.parent().find('a span');\n  var spanText = spanTitle.text();\n  var newVal = titleInput.val();\n  if (spanText != newVal) {\n    spanTitle.text(newVal);\n    var blobRef = titleInput.parent().attr('id').replace(/^camli-/, '');\n    camliNewSetAttributeClaim(\n      blobRef,\n      \"title\",\n      newVal,\n      {\n          success: function() {\n              titleInput.hide();\n              spanTitle.show();\n              spanTitle.effect('highlight', {}, 300);\n          },\n          fail: function(msg) {\n              alert(msg);\n          }\n      });\n  }\n  titleInput.hide();\n  spanTitle.show();\n}\n\n// Installs jQuery and the colorbox library along with an onload listener\n// to fire the init function above.\nif (typeof window['jQuery'] == 'undefined') {\n  document.write('');\n  document.write('');\n  document.write('');\n  document.write('');\n}\n", time.Unix(0, 1310770714000000000));
 }
diff --git a/server/camlistored/ui/zembed_search.html.go b/server/camlistored/ui/zembed_search.html.go
index b3ef1a3c3..a8bb67342 100644
--- a/server/camlistored/ui/zembed_search.html.go
+++ b/server/camlistored/ui/zembed_search.html.go
@@ -1,6 +1,7 @@
 // THIS FILE IS AUTO-GENERATED FROM search.html
 // DO NOT EDIT.
 package ui
+import "time"
 func init() {
-	Files.Add("search.html", "\n\n  Camlistored UI\n  \n  \n  \n  \n  \n  \n\n\n    \n\n    

Search

\n\n

In all attributes

\n
\n \n \n
\n\n

By Tag

\n
\n \n \n
\n\n

By Title

\n
\n \n \n
\n\n

Search

\n
\n
\n

\n

\n \n or\n
\n \n

\n\n\n\n"); + Files.Add("search.html", "\n\n Camlistored UI\n \n \n \n \n \n \n\n\n \n\n

Search

\n\n

In all attributes

\n
\n \n \n
\n\n

By Tag

\n
\n \n \n
\n\n

By Title

\n
\n \n \n
\n\n

Search

\n
\n
\n

\n

\n \n or\n
\n \n

\n\n\n\n", time.Unix(0, 1316041554000000000)); } diff --git a/server/camlistored/ui/zembed_search.js.go b/server/camlistored/ui/zembed_search.js.go index 2e80dd9f2..eb5e75594 100644 --- a/server/camlistored/ui/zembed_search.js.go +++ b/server/camlistored/ui/zembed_search.js.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM search.js // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("search.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nvar CamliSearch = {};\n\nfunction getSearchParams() {\n\tCamliSearch.query = \"\";\n\tCamliSearch.type = \"\";\n\tCamliSearch.fuzzy = \"\";\n\tCamliSearch.query = getQueryParam('q');\n\tCamliSearch.type = getQueryParam('t');\n\tCamliSearch.fuzzy = getQueryParam('f');\n\tif (CamliSearch.type == null) {\n\t\tCamliSearch.type = \"\";\n\t}\n\tif (CamliSearch.fuzzy == null) {\n\t\tCamliSearch.fuzzy = \"\";\n\t}\n}\n\nfunction hideAllResThings() {\n\tCamliSearch.titleRes.style.visibility = 'hidden';\n\tCamliSearch.btnNewCollec.disabled = true;\n\tCamliSearch.btnNewCollec.style.visibility = 'hidden';\n\tCamliSearch.formAddToCollec.style.visibility = 'hidden';\n}\n\nfunction handleFormGetTagged(e) {\n\te.stopPropagation();\n\te.preventDefault();\n\n\tvar input = document.getElementById(\"inputTag\");\n\n\tif (input.value == \"\") {\n\t\treturn;\n\t}\n\n\tvar tags = input.value.split(/\\s*,\\s*/);\n\tdocument.location.href = \"search.html?q=\" + tags[0] + \"&t=tag\"\n}\n\nfunction handleFormGetTitled(e) {\n\te.stopPropagation();\n\te.preventDefault();\n\n\tvar input = document.getElementById(\"inputTitle\");\n\n\tif (input.value == \"\") {\n\t\treturn;\n\t}\n\n\tvar titles = input.value.split(/\\s*,\\s*/);\n\tdocument.location.href = \"search.html?q=\" + titles[0] + \"&t=title\"\n}\n\nfunction handleFormGetAnyAttr(e) {\n\te.stopPropagation();\n\te.preventDefault();\n\n\tvar input = document.getElementById(\"inputAnyAttr\");\n\n\tif (input.value == \"\") {\n\t\treturn;\n\t}\n\n\tvar any = input.value.split(/\\s*,\\s*/);\n\tdocument.location.href = \"search.html?q=\" + any[0]\n}\n\nfunction doSearch() {\n\tvar sigcb = {};\n\tsigcb.success = function(sigconf) {\n\t\tvar tagcb = {};\n\t\ttagcb.success = function(pres) {\n\t\t\tshowSearchResult(pres, CamliSearch.type);\n\t\t};\n\t\ttagcb.fail = function(msg) {\n\t\t\talert(msg);\n\t\t};\n// TODO(mpl): add other kinds of searches (by filename for ex).\n\t\tswitch(CamliSearch.type) {\n\t\tcase \"tag\":\n\t\t\tcamliGetPermanodesWithAttr(sigconf.publicKeyBlobRef, \"tag\", CamliSearch.query, CamliSearch.fuzzy, tagcb);\n\t\t\tbreak;\n\t\tcase \"title\":\n\t\t\tcamliGetPermanodesWithAttr(sigconf.publicKeyBlobRef, \"title\", CamliSearch.query, \"true\", tagcb);\n\t\t\tbreak;\n\t\tcase \"\":\n\t\t\tcamliGetPermanodesWithAttr(sigconf.publicKeyBlobRef, \"\", CamliSearch.query, \"true\", tagcb);\n\t\t\tbreak;\n\t\t}\n\t};\n\tsigcb.fail = function() {\n\t\talert(\"sig disco failed\");\n\t}\n\tcamliSigDiscovery(sigcb);\n}\n\nfunction showSearchResult(pres, type) {\n\tshowPermanodes(pres, type);\n\tCamliSearch.query = \"\";\n\tCamliSearch.type = \"\";\n}\n\nfunction showPermanodes(searchRes, type) {\n\tvar div = document.getElementById(\"divRes\");\n\twhile (div.hasChildNodes()) {\n\t\tdiv.removeChild(div.lastChild);\n\t}\n\tvar results = searchRes.withAttr;\n\tif (results.length > 0) {\n\t\tvar checkall = document.createElement(\"input\");\n\t\tcheckall.id = \"checkall\";\n\t\tcheckall.type = \"checkbox\";\n\t\tcheckall.name = \"checkall\";\n\t\tcheckall.checked = false;\n\t\tcheckall.onclick = Function(\"checkAll();\");\n\t\tdiv.appendChild(checkall);\n\t\tdiv.appendChild(document.createElement(\"br\"));\n\t}\n\tfor (var i = 0; i < results.length; i++) {\n\t\tvar result = results[i];\n\t\tvar alink = document.createElement(\"a\");\n\t\talink.href = \"./?p=\" + result.permanode;\n\t\talink.innerText = camliBlobTitle(result.permanode, searchRes);\n\t\tvar cbox = document.createElement('input');\n\t\tcbox.type = \"checkbox\";\n\t\tcbox.name = \"checkbox\";\n\t\tcbox.value = result.permanode;\n\t\tdiv.appendChild(cbox);\n\t\tdiv.appendChild(alink);\n\t\tdiv.appendChild(document.createElement('br'));\n\t}\n\tif (results.length > 0) {\n\t\tswitch(type) {\n\t\tcase \"tag\":\n\t\t\tCamliSearch.titleRes.innerHTML = \"Tagged with \\\"\";\n\t\t\tbreak;\n\t\tcase \"title\":\n\t\t\tCamliSearch.titleRes.innerHTML = \"Titled with \\\"\";\n\t\t\tbreak;\n\t\tcase \"\":\n\t\t\tCamliSearch.titleRes.innerHTML = \"General search for \\\"\";\n\t\t\tbreak;\n\t\t}\n\t\tCamliSearch.titleRes.innerHTML += CamliSearch.query + \"\\\"\";\n\t\tCamliSearch.titleRes.style.visibility = 'visible';\n\t\tCamliSearch.btnNewCollec.disabled = false;\n\t\tCamliSearch.btnNewCollec.style.visibility = 'visible';\n\t\tCamliSearch.formAddToCollec.style.visibility = 'visible';\n\t} else {\n\t\thideAllResThings();\n\t}\n}\n\nfunction getTicked() {\n\tvar checkboxes = document.getElementsByName(\"checkbox\");\n\tCamliSearch.tickedMemb = new Array();\n\tvar j = 0;\n\tfor (var i = 0; i < checkboxes.length; i++) {\n\t\tif (checkboxes[i].checked) {\n\t\t\tCamliSearch.tickedMemb[j] = checkboxes[i].value;\n\t\t\tj++;\n\t\t}\n\t}\n}\n\nfunction checkAll() {\n\tvar checkall = document.getElementById(\"checkall\");\n\tvar checkboxes = document.getElementsByName('checkbox');\n\tfor (var i = 0; i < checkboxes.length; i++) {\n\t\tcheckboxes[i].checked = checkall.checked;\n\t}\n}\n\nfunction handleCreateNewCollection(e) {\n\taddToCollection(true)\n}\n\nfunction handleAddToCollection(e) {\n\te.stopPropagation();\n\te.preventDefault();\n\taddToCollection(false)\n}\n\nfunction addToCollection(createNew) {\n\tvar cnpcb = {};\n\tcnpcb.success = function(parent) {\n\t\tvar nRemain = CamliSearch.tickedMemb.length;\n\t\tvar naaccb = {};\n\t\tnaaccb.fail = function() {\n\t\t\tCamliSearch.btnNewCollec.disabled = true;\n\t\t\tthrow(\"failed to add member to collection\");\n\t\t}\n\t\tnaaccb.success = function() {\n\t\t\tnRemain--;\n\t\t\tif (nRemain == 0) {\n\t\t\t\tCamliSearch.btnNewCollec.disabled = true;\n\t\t\t\twindow.location = \"./?p=\" + parent;\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tfor (var i = 0; i < CamliSearch.tickedMemb.length; i++) {\n\t\t\t\tcamliNewAddAttributeClaim(parent, \"camliMember\", CamliSearch.tickedMemb[i], naaccb);\n\t\t\t}\n\t\t} catch(x) {\n\t\t\talert(x)\n\t\t}\n\t};\n\tcnpcb.fail = function() {\n\t\talert(\"failed to create permanode\");\n\t};\n\tgetTicked();\n\tif (CamliSearch.tickedMemb.length > 0) {\n\t\tif (createNew) {\n\t\t\tcamliCreateNewPermanode(cnpcb);\n\t\t} else {\n\t\t\tvar pn = document.getElementById(\"inputCollec\").value;\n//TODO(mpl): allow a collection title (instead of a hash) as input\n\t\t\tif (!isPlausibleBlobRef(pn)) {\n\t\t\t\talert(\"Not a valid collection permanode hash\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar returnPn = function(opts) {\n\t\t\t\topts = saneOpts(opts);\n\t\t\t\topts.success(pn);\n\t\t\t}\n\t\t\treturnPn(cnpcb);\n\t\t}\n\t} else {\n\t\talert(\"No selected object\")\n\t}\n}\n\nfunction indexOnLoad(e) {\n\n\tvar formTags = document.getElementById(\"formTags\");\n\tformTags.addEventListener(\"submit\", handleFormGetTagged);\n\tvar formTitles = document.getElementById(\"formTitles\");\n\tformTitles.addEventListener(\"submit\", handleFormGetTitled);\n\tvar formAnyAttr = document.getElementById(\"formAnyAttr\");\n\tformAnyAttr.addEventListener(\"submit\", handleFormGetAnyAttr);\n\tCamliSearch.titleRes = document.getElementById(\"titleRes\");\n\tCamliSearch.btnNewCollec = document.getElementById(\"btnNewCollec\");\n\tCamliSearch.btnNewCollec.addEventListener(\"click\", handleCreateNewCollection);\n\tCamliSearch.formAddToCollec = document.getElementById(\"formAddToCollec\");\n\tCamliSearch.formAddToCollec.addEventListener(\"submit\", handleAddToCollection);\n\thideAllResThings();\n\tgetSearchParams();\n\tif (CamliSearch.query != \"\") {\n\t\tdoSearch();\n\t}\n}\n\nwindow.addEventListener(\"load\", indexOnLoad);\n"); + Files.Add("search.js", "/*\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n*/\n\nvar CamliSearch = {};\n\nfunction getSearchParams() {\n\tCamliSearch.query = \"\";\n\tCamliSearch.type = \"\";\n\tCamliSearch.fuzzy = \"\";\n\tCamliSearch.query = getQueryParam('q');\n\tCamliSearch.type = getQueryParam('t');\n\tCamliSearch.fuzzy = getQueryParam('f');\n\tif (CamliSearch.type == null) {\n\t\tCamliSearch.type = \"\";\n\t}\n\tif (CamliSearch.fuzzy == null) {\n\t\tCamliSearch.fuzzy = \"\";\n\t}\n}\n\nfunction hideAllResThings() {\n\tCamliSearch.titleRes.style.visibility = 'hidden';\n\tCamliSearch.btnNewCollec.disabled = true;\n\tCamliSearch.btnNewCollec.style.visibility = 'hidden';\n\tCamliSearch.formAddToCollec.style.visibility = 'hidden';\n}\n\nfunction handleFormGetTagged(e) {\n\te.stopPropagation();\n\te.preventDefault();\n\n\tvar input = document.getElementById(\"inputTag\");\n\n\tif (input.value == \"\") {\n\t\treturn;\n\t}\n\n\tvar tags = input.value.split(/\\s*,\\s*/);\n\tdocument.location.href = \"search.html?q=\" + tags[0] + \"&t=tag\"\n}\n\nfunction handleFormGetTitled(e) {\n\te.stopPropagation();\n\te.preventDefault();\n\n\tvar input = document.getElementById(\"inputTitle\");\n\n\tif (input.value == \"\") {\n\t\treturn;\n\t}\n\n\tvar titles = input.value.split(/\\s*,\\s*/);\n\tdocument.location.href = \"search.html?q=\" + titles[0] + \"&t=title\"\n}\n\nfunction handleFormGetAnyAttr(e) {\n\te.stopPropagation();\n\te.preventDefault();\n\n\tvar input = document.getElementById(\"inputAnyAttr\");\n\n\tif (input.value == \"\") {\n\t\treturn;\n\t}\n\n\tvar any = input.value.split(/\\s*,\\s*/);\n\tdocument.location.href = \"search.html?q=\" + any[0]\n}\n\nfunction doSearch() {\n\tvar sigcb = {};\n\tsigcb.success = function(sigconf) {\n\t\tvar tagcb = {};\n\t\ttagcb.success = function(pres) {\n\t\t\tshowSearchResult(pres, CamliSearch.type);\n\t\t};\n\t\ttagcb.fail = function(msg) {\n\t\t\talert(msg);\n\t\t};\n// TODO(mpl): add other kinds of searches (by filename for ex).\n\t\tswitch(CamliSearch.type) {\n\t\tcase \"tag\":\n\t\t\tcamliGetPermanodesWithAttr(sigconf.publicKeyBlobRef, \"tag\", CamliSearch.query, CamliSearch.fuzzy, tagcb);\n\t\t\tbreak;\n\t\tcase \"title\":\n\t\t\tcamliGetPermanodesWithAttr(sigconf.publicKeyBlobRef, \"title\", CamliSearch.query, \"true\", tagcb);\n\t\t\tbreak;\n\t\tcase \"\":\n\t\t\tcamliGetPermanodesWithAttr(sigconf.publicKeyBlobRef, \"\", CamliSearch.query, \"true\", tagcb);\n\t\t\tbreak;\n\t\t}\n\t};\n\tsigcb.fail = function() {\n\t\talert(\"sig disco failed\");\n\t}\n\tcamliSigDiscovery(sigcb);\n}\n\nfunction showSearchResult(pres, type) {\n\tshowPermanodes(pres, type);\n\tCamliSearch.query = \"\";\n\tCamliSearch.type = \"\";\n}\n\nfunction showPermanodes(searchRes, type) {\n\tvar div = document.getElementById(\"divRes\");\n\twhile (div.hasChildNodes()) {\n\t\tdiv.removeChild(div.lastChild);\n\t}\n\tvar results = searchRes.withAttr;\n\tif (results.length > 0) {\n\t\tvar checkall = document.createElement(\"input\");\n\t\tcheckall.id = \"checkall\";\n\t\tcheckall.type = \"checkbox\";\n\t\tcheckall.name = \"checkall\";\n\t\tcheckall.checked = false;\n\t\tcheckall.onclick = Function(\"checkAll();\");\n\t\tdiv.appendChild(checkall);\n\t\tdiv.appendChild(document.createElement(\"br\"));\n\t}\n\tfor (var i = 0; i < results.length; i++) {\n\t\tvar result = results[i];\n\t\tvar alink = document.createElement(\"a\");\n\t\talink.href = \"./?p=\" + result.permanode;\n\t\talink.innerText = camliBlobTitle(result.permanode, searchRes);\n\t\tvar cbox = document.createElement('input');\n\t\tcbox.type = \"checkbox\";\n\t\tcbox.name = \"checkbox\";\n\t\tcbox.value = result.permanode;\n\t\tdiv.appendChild(cbox);\n\t\tdiv.appendChild(alink);\n\t\tdiv.appendChild(document.createElement('br'));\n\t}\n\tif (results.length > 0) {\n\t\tswitch(type) {\n\t\tcase \"tag\":\n\t\t\tCamliSearch.titleRes.innerHTML = \"Tagged with \\\"\";\n\t\t\tbreak;\n\t\tcase \"title\":\n\t\t\tCamliSearch.titleRes.innerHTML = \"Titled with \\\"\";\n\t\t\tbreak;\n\t\tcase \"\":\n\t\t\tCamliSearch.titleRes.innerHTML = \"General search for \\\"\";\n\t\t\tbreak;\n\t\t}\n\t\tCamliSearch.titleRes.innerHTML += CamliSearch.query + \"\\\"\";\n\t\tCamliSearch.titleRes.style.visibility = 'visible';\n\t\tCamliSearch.btnNewCollec.disabled = false;\n\t\tCamliSearch.btnNewCollec.style.visibility = 'visible';\n\t\tCamliSearch.formAddToCollec.style.visibility = 'visible';\n\t} else {\n\t\thideAllResThings();\n\t}\n}\n\nfunction getTicked() {\n\tvar checkboxes = document.getElementsByName(\"checkbox\");\n\tCamliSearch.tickedMemb = new Array();\n\tvar j = 0;\n\tfor (var i = 0; i < checkboxes.length; i++) {\n\t\tif (checkboxes[i].checked) {\n\t\t\tCamliSearch.tickedMemb[j] = checkboxes[i].value;\n\t\t\tj++;\n\t\t}\n\t}\n}\n\nfunction checkAll() {\n\tvar checkall = document.getElementById(\"checkall\");\n\tvar checkboxes = document.getElementsByName('checkbox');\n\tfor (var i = 0; i < checkboxes.length; i++) {\n\t\tcheckboxes[i].checked = checkall.checked;\n\t}\n}\n\nfunction handleCreateNewCollection(e) {\n\taddToCollection(true)\n}\n\nfunction handleAddToCollection(e) {\n\te.stopPropagation();\n\te.preventDefault();\n\taddToCollection(false)\n}\n\nfunction addToCollection(createNew) {\n\tvar cnpcb = {};\n\tcnpcb.success = function(parent) {\n\t\tvar nRemain = CamliSearch.tickedMemb.length;\n\t\tvar naaccb = {};\n\t\tnaaccb.fail = function() {\n\t\t\tCamliSearch.btnNewCollec.disabled = true;\n\t\t\tthrow(\"failed to add member to collection\");\n\t\t}\n\t\tnaaccb.success = function() {\n\t\t\tnRemain--;\n\t\t\tif (nRemain == 0) {\n\t\t\t\tCamliSearch.btnNewCollec.disabled = true;\n\t\t\t\twindow.location = \"./?p=\" + parent;\n\t\t\t}\n\t\t}\n\t\ttry {\n\t\t\tfor (var i = 0; i < CamliSearch.tickedMemb.length; i++) {\n\t\t\t\tcamliNewAddAttributeClaim(parent, \"camliMember\", CamliSearch.tickedMemb[i], naaccb);\n\t\t\t}\n\t\t} catch(x) {\n\t\t\talert(x)\n\t\t}\n\t};\n\tcnpcb.fail = function() {\n\t\talert(\"failed to create permanode\");\n\t};\n\tgetTicked();\n\tif (CamliSearch.tickedMemb.length > 0) {\n\t\tif (createNew) {\n\t\t\tcamliCreateNewPermanode(cnpcb);\n\t\t} else {\n\t\t\tvar pn = document.getElementById(\"inputCollec\").value;\n//TODO(mpl): allow a collection title (instead of a hash) as input\n\t\t\tif (!isPlausibleBlobRef(pn)) {\n\t\t\t\talert(\"Not a valid collection permanode hash\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar returnPn = function(opts) {\n\t\t\t\topts = saneOpts(opts);\n\t\t\t\topts.success(pn);\n\t\t\t}\n\t\t\treturnPn(cnpcb);\n\t\t}\n\t} else {\n\t\talert(\"No selected object\")\n\t}\n}\n\nfunction indexOnLoad(e) {\n\n\tvar formTags = document.getElementById(\"formTags\");\n\tformTags.addEventListener(\"submit\", handleFormGetTagged);\n\tvar formTitles = document.getElementById(\"formTitles\");\n\tformTitles.addEventListener(\"submit\", handleFormGetTitled);\n\tvar formAnyAttr = document.getElementById(\"formAnyAttr\");\n\tformAnyAttr.addEventListener(\"submit\", handleFormGetAnyAttr);\n\tCamliSearch.titleRes = document.getElementById(\"titleRes\");\n\tCamliSearch.btnNewCollec = document.getElementById(\"btnNewCollec\");\n\tCamliSearch.btnNewCollec.addEventListener(\"click\", handleCreateNewCollection);\n\tCamliSearch.formAddToCollec = document.getElementById(\"formAddToCollec\");\n\tCamliSearch.formAddToCollec.addEventListener(\"submit\", handleAddToCollection);\n\thideAllResThings();\n\tgetSearchParams();\n\tif (CamliSearch.query != \"\") {\n\t\tdoSearch();\n\t}\n}\n\nwindow.addEventListener(\"load\", indexOnLoad);\n", time.Unix(0, 1323040624000000000)); } diff --git a/server/camlistored/ui/zembed_sigdebug.js.go b/server/camlistored/ui/zembed_sigdebug.js.go index caa0d54c3..8ff232690 100644 --- a/server/camlistored/ui/zembed_sigdebug.js.go +++ b/server/camlistored/ui/zembed_sigdebug.js.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM sigdebug.js // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("sigdebug.js", "var sigdisco = null;\n\nfunction discoverJsonSign() {\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n console.log(\"no status 200; got \" + xhr.status);\n return;\n }\n sigdisco = JSON.parse(xhr.responseText);\n document.getElementById(\"sigdiscores\").innerHTML = \"
\" + JSON.stringify(sigdisco, null, 2) + \"
\";\n };\n xhr.open(\"GET\", disco.jsonSignRoot + \"/camli/sig/discovery\", true);\n xhr.send();\n}\n\nfunction addKeyRef() {\n if (!sigdisco) {\n alert(\"must do jsonsign discovery first\"); \n return;\n }\n clearta = document.getElementById(\"clearjson\");\n var j;\n try {\n j = JSON.parse(clearta.value);\n } catch (x) {\n alert(x);\n return\n }\n j.camliSigner = sigdisco.publicKeyBlobRef;\n clearta.value = JSON.stringify(j);\n}\n\nfunction doSign() {\n if (!sigdisco) {\n alert(\"must do jsonsign discovery first\");\n return;\n }\n clearta = document.getElementById(\"clearjson\");\n\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n alert(\"got status \" + xhr.status)\n return;\n }\n document.getElementById(\"signedjson\").value = xhr.responseText;\n };\n xhr.open(\"POST\", sigdisco.signHandler, true);\n xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n xhr.send(\"json=\" + encodeURIComponent(clearta.value));\n}\n\nfunction doVerify() {\n if (!sigdisco) {\n alert(\"must do jsonsign discovery first\");\n return;\n }\n\n signedta = document.getElementById(\"signedjson\");\n\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n alert(\"got status \" + xhr.status)\n return;\n }\n document.getElementById(\"verifyinfo\").innerHTML = \"
\" + xhr.responseText + \"
\";\n };\n xhr.open(\"POST\", sigdisco.verifyHandler, true);\n xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n xhr.send(\"sjson=\" + encodeURIComponent(signedta.value));\n}\n"); + Files.Add("sigdebug.js", "var sigdisco = null;\n\nfunction discoverJsonSign() {\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n console.log(\"no status 200; got \" + xhr.status);\n return;\n }\n sigdisco = JSON.parse(xhr.responseText);\n document.getElementById(\"sigdiscores\").innerHTML = \"
\" + JSON.stringify(sigdisco, null, 2) + \"
\";\n };\n xhr.open(\"GET\", disco.jsonSignRoot + \"/camli/sig/discovery\", true);\n xhr.send();\n}\n\nfunction addKeyRef() {\n if (!sigdisco) {\n alert(\"must do jsonsign discovery first\"); \n return;\n }\n clearta = document.getElementById(\"clearjson\");\n var j;\n try {\n j = JSON.parse(clearta.value);\n } catch (x) {\n alert(x);\n return\n }\n j.camliSigner = sigdisco.publicKeyBlobRef;\n clearta.value = JSON.stringify(j);\n}\n\nfunction doSign() {\n if (!sigdisco) {\n alert(\"must do jsonsign discovery first\");\n return;\n }\n clearta = document.getElementById(\"clearjson\");\n\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n alert(\"got status \" + xhr.status)\n return;\n }\n document.getElementById(\"signedjson\").value = xhr.responseText;\n };\n xhr.open(\"POST\", sigdisco.signHandler, true);\n xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n xhr.send(\"json=\" + encodeURIComponent(clearta.value));\n}\n\nfunction doVerify() {\n if (!sigdisco) {\n alert(\"must do jsonsign discovery first\");\n return;\n }\n\n signedta = document.getElementById(\"signedjson\");\n\n var xhr = new XMLHttpRequest();\n xhr.onreadystatechange = function() {\n if (xhr.readyState != 4) { return; }\n if (xhr.status != 200) {\n alert(\"got status \" + xhr.status)\n return;\n }\n document.getElementById(\"verifyinfo\").innerHTML = \"
\" + xhr.responseText + \"
\";\n };\n xhr.open(\"POST\", sigdisco.verifyHandler, true);\n xhr.setRequestHeader(\"Content-Type\", \"application/x-www-form-urlencoded\");\n xhr.send(\"sjson=\" + encodeURIComponent(signedta.value));\n}\n", time.Unix(0, 1309407835000000000)); } diff --git a/server/camlistored/ui/zembed_signing.html.go b/server/camlistored/ui/zembed_signing.html.go index 32e03c806..080a28957 100644 --- a/server/camlistored/ui/zembed_signing.html.go +++ b/server/camlistored/ui/zembed_signing.html.go @@ -1,6 +1,7 @@ // THIS FILE IS AUTO-GENERATED FROM signing.html // DO NOT EDIT. package ui +import "time" func init() { - Files.Add("signing.html", "\n\n Camlistored UI\n \n \n \n\n\n

Signing Debug

\n
\n

\n
(jsonsign discovery results)
\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
JSON blob to sign: Signed blob:Verification details:
\n
\n\n\n\n"); + Files.Add("signing.html", "\n\n Camlistored UI\n \n \n \n\n\n

Signing Debug

\n
\n

\n
(jsonsign discovery results)
\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
JSON blob to sign: Signed blob:Verification details:
\n
\n\n\n\n", time.Unix(0, 1307659868000000000)); }