Statistics
| Branch: | Tag: | Revision:

root / snf-cyclades-app / synnefo / ui / static / snf / js / utils.js @ f5c5fb5e

History | View | Annotate | Download (20.9 kB)

1 00469232 Kostas Papadimitriou
// Copyright 2011 GRNET S.A. All rights reserved.
2 00469232 Kostas Papadimitriou
// 
3 00469232 Kostas Papadimitriou
// Redistribution and use in source and binary forms, with or
4 00469232 Kostas Papadimitriou
// without modification, are permitted provided that the following
5 00469232 Kostas Papadimitriou
// conditions are met:
6 00469232 Kostas Papadimitriou
// 
7 00469232 Kostas Papadimitriou
//   1. Redistributions of source code must retain the above
8 00469232 Kostas Papadimitriou
//      copyright notice, this list of conditions and the following
9 00469232 Kostas Papadimitriou
//      disclaimer.
10 00469232 Kostas Papadimitriou
// 
11 00469232 Kostas Papadimitriou
//   2. Redistributions in binary form must reproduce the above
12 00469232 Kostas Papadimitriou
//      copyright notice, this list of conditions and the following
13 00469232 Kostas Papadimitriou
//      disclaimer in the documentation and/or other materials
14 00469232 Kostas Papadimitriou
//      provided with the distribution.
15 00469232 Kostas Papadimitriou
// 
16 00469232 Kostas Papadimitriou
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 00469232 Kostas Papadimitriou
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 00469232 Kostas Papadimitriou
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 00469232 Kostas Papadimitriou
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 00469232 Kostas Papadimitriou
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 00469232 Kostas Papadimitriou
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 00469232 Kostas Papadimitriou
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 00469232 Kostas Papadimitriou
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 00469232 Kostas Papadimitriou
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 00469232 Kostas Papadimitriou
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 00469232 Kostas Papadimitriou
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 00469232 Kostas Papadimitriou
// POSSIBILITY OF SUCH DAMAGE.
28 00469232 Kostas Papadimitriou
// 
29 00469232 Kostas Papadimitriou
// The views and conclusions contained in the software and
30 00469232 Kostas Papadimitriou
// documentation are those of the authors and should not be
31 00469232 Kostas Papadimitriou
// interpreted as representing official policies, either expressed
32 00469232 Kostas Papadimitriou
// or implied, of GRNET S.A.
33 00469232 Kostas Papadimitriou
// 
34 00469232 Kostas Papadimitriou
35 8d08f18a Kostas Papadimitriou
;(function(root){
36 8d08f18a Kostas Papadimitriou
    
37 8d08f18a Kostas Papadimitriou
    var root = root;
38 8d08f18a Kostas Papadimitriou
    var snf = root.synnefo = root.synnefo || {};
39 8d08f18a Kostas Papadimitriou
    
40 8d08f18a Kostas Papadimitriou
    snf.i18n = {};
41 8d08f18a Kostas Papadimitriou
42 8d08f18a Kostas Papadimitriou
    // Logging namespace
43 8d08f18a Kostas Papadimitriou
    var logging = snf.logging = snf.logging || {};
44 8d08f18a Kostas Papadimitriou
45 8d08f18a Kostas Papadimitriou
    // logger object
46 8d08f18a Kostas Papadimitriou
    var logger = logging.logger = function(ns, level){
47 8d08f18a Kostas Papadimitriou
        var levels = ["debug", "info", "error"];
48 8d08f18a Kostas Papadimitriou
        var con = window.console;
49 8d08f18a Kostas Papadimitriou
        
50 8d08f18a Kostas Papadimitriou
        this.level = level || synnefo.logging.level;
51 8d08f18a Kostas Papadimitriou
        this.ns = ns || "";
52 8d08f18a Kostas Papadimitriou
53 8d08f18a Kostas Papadimitriou
        this._log = function(lvl) {
54 8d08f18a Kostas Papadimitriou
            if (lvl >= this.level && con) {
55 8d08f18a Kostas Papadimitriou
                var args = Array.prototype.slice.call(arguments[1]);
56 8d08f18a Kostas Papadimitriou
                var level_name = levels[lvl];
57 8d08f18a Kostas Papadimitriou
                    
58 8d08f18a Kostas Papadimitriou
                if (this.ns) {
59 8d08f18a Kostas Papadimitriou
                    args = ["["+this.ns+"] "].concat(args);
60 8d08f18a Kostas Papadimitriou
                }
61 8d08f18a Kostas Papadimitriou
62 8d08f18a Kostas Papadimitriou
                log = con.log
63 8d08f18a Kostas Papadimitriou
                if (con[level_name])
64 8d08f18a Kostas Papadimitriou
                    log = con[level_name]
65 8d08f18a Kostas Papadimitriou
66 8d08f18a Kostas Papadimitriou
                try {
67 8d08f18a Kostas Papadimitriou
                    con && log.apply(con, Array.prototype.slice.call(args));
68 8d08f18a Kostas Papadimitriou
                } catch (err) {}
69 8d08f18a Kostas Papadimitriou
            }
70 8d08f18a Kostas Papadimitriou
        }
71 8d08f18a Kostas Papadimitriou
72 8d08f18a Kostas Papadimitriou
        this.debug = function() {
73 8d08f18a Kostas Papadimitriou
            var args = [0]; args.push.call(args, arguments);
74 8d08f18a Kostas Papadimitriou
            this._log.apply(this, args);
75 8d08f18a Kostas Papadimitriou
        }
76 8d08f18a Kostas Papadimitriou
77 8d08f18a Kostas Papadimitriou
        this.info = function() {
78 8d08f18a Kostas Papadimitriou
            var args = [1]; args.push.call(args, arguments);
79 8d08f18a Kostas Papadimitriou
            this._log.apply(this, args);
80 8d08f18a Kostas Papadimitriou
        }
81 8d08f18a Kostas Papadimitriou
82 8d08f18a Kostas Papadimitriou
        this.error = function() {
83 8d08f18a Kostas Papadimitriou
            var args = [2]; args.push.call(args, arguments);
84 8d08f18a Kostas Papadimitriou
            this._log.apply(this, args);
85 8d08f18a Kostas Papadimitriou
        }
86 8d08f18a Kostas Papadimitriou
87 8d08f18a Kostas Papadimitriou
    };
88 8d08f18a Kostas Papadimitriou
    
89 8d08f18a Kostas Papadimitriou
    synnefo.collect_user_data = function() {
90 8d08f18a Kostas Papadimitriou
        var data = {}
91 8d08f18a Kostas Papadimitriou
        
92 8d08f18a Kostas Papadimitriou
        try {
93 9ffd10ce Kostas Papadimitriou
            data.client = {'browser': $.browser, 'screen': $.extend({}, screen), 'client': $.client}
94 9ffd10ce Kostas Papadimitriou
        } catch (err) { data.client = err }
95 9ffd10ce Kostas Papadimitriou
        try {
96 8d08f18a Kostas Papadimitriou
            data.calls = synnefo.api.requests;
97 8d08f18a Kostas Papadimitriou
        } catch (err) { data.calls = err }
98 8d08f18a Kostas Papadimitriou
        try {
99 8d08f18a Kostas Papadimitriou
            data.errors = synnefo.api.errors;
100 8d08f18a Kostas Papadimitriou
        } catch (err) { data.errors = err }
101 8d08f18a Kostas Papadimitriou
        try {
102 8d08f18a Kostas Papadimitriou
            data.data = {};
103 8d08f18a Kostas Papadimitriou
        } catch (err) { data.data = err }
104 8d08f18a Kostas Papadimitriou
        try {
105 8d08f18a Kostas Papadimitriou
            data.data.vms = synnefo.storage.vms.toJSON();
106 8d08f18a Kostas Papadimitriou
        } catch (err) { data.data.vms = err }
107 8d08f18a Kostas Papadimitriou
        try {
108 9ffd10ce Kostas Papadimitriou
            data.data.networks = synnefo.storage.networks.toJSON();
109 8d08f18a Kostas Papadimitriou
        } catch (err) { data.data.networks = err }
110 9ffd10ce Kostas Papadimitriou
        //try {
111 9ffd10ce Kostas Papadimitriou
            //data.data.images = synnefo.storage.images.toJSON();
112 9ffd10ce Kostas Papadimitriou
        //} catch (err) { data.data.images = err }
113 9ffd10ce Kostas Papadimitriou
        //try {
114 9ffd10ce Kostas Papadimitriou
            //data.data.flavors = synnefo.storage.flavors.toJSON();
115 9ffd10ce Kostas Papadimitriou
        //} catch (err) { data.data.flavors = err }
116 8d08f18a Kostas Papadimitriou
        try {
117 8d08f18a Kostas Papadimitriou
            data.date = new Date;
118 8d08f18a Kostas Papadimitriou
        } catch (err) { data.date = err }
119 8d08f18a Kostas Papadimitriou
120 8d08f18a Kostas Papadimitriou
        return data;
121 8d08f18a Kostas Papadimitriou
    }
122 8d08f18a Kostas Papadimitriou
123 8d08f18a Kostas Papadimitriou
    // default logger level (debug)
124 8d08f18a Kostas Papadimitriou
    synnefo.logging.level = 0;
125 8d08f18a Kostas Papadimitriou
126 8d08f18a Kostas Papadimitriou
    // generic logger
127 8d08f18a Kostas Papadimitriou
    synnefo.log = new logger({'ns':'SNF'});
128 8d08f18a Kostas Papadimitriou
129 8d08f18a Kostas Papadimitriou
    // synnefo config options
130 8d08f18a Kostas Papadimitriou
    synnefo.config = synnefo.config || {};
131 8d08f18a Kostas Papadimitriou
    synnefo.config.api_url = "/api/v1.1";
132 8d08f18a Kostas Papadimitriou
    
133 8d08f18a Kostas Papadimitriou
    // Util namespace
134 8d08f18a Kostas Papadimitriou
    synnefo.util = synnefo.util || {};
135 1e882dd7 Kostas Papadimitriou
    
136 1e882dd7 Kostas Papadimitriou
    synnefo.util.FormatDigits = function(num, length) {
137 1e882dd7 Kostas Papadimitriou
        var r = "" + num;
138 1e882dd7 Kostas Papadimitriou
        while (r.length < length) {
139 1e882dd7 Kostas Papadimitriou
            r = "0" + r;
140 1e882dd7 Kostas Papadimitriou
        }
141 1e882dd7 Kostas Papadimitriou
        return r;
142 1e882dd7 Kostas Papadimitriou
    }
143 1e882dd7 Kostas Papadimitriou
144 1e882dd7 Kostas Papadimitriou
    synnefo.util.formatDate = function(d) {
145 1e882dd7 Kostas Papadimitriou
        var dt = synnefo.util.FormatDigits(d.getDate()) + '/';
146 1e882dd7 Kostas Papadimitriou
        dt += synnefo.util.FormatDigits(d.getMonth(), 2);
147 1e882dd7 Kostas Papadimitriou
        dt += '/' + d.getFullYear();
148 1e882dd7 Kostas Papadimitriou
        dt += ' ' + synnefo.util.FormatDigits(d.getHours(), 2) + ':';
149 1e882dd7 Kostas Papadimitriou
        dt += synnefo.util.FormatDigits(d.getMinutes(), 2) + ':';
150 1e882dd7 Kostas Papadimitriou
        dt += synnefo.util.FormatDigits(d.getSeconds(), 2);
151 1e882dd7 Kostas Papadimitriou
        return dt;
152 1e882dd7 Kostas Papadimitriou
    },
153 8d08f18a Kostas Papadimitriou
154 8d08f18a Kostas Papadimitriou
    // Extensions and Utility functions
155 8d08f18a Kostas Papadimitriou
    synnefo.util.ISODateString = function(d){
156 8d08f18a Kostas Papadimitriou
        function pad(n){
157 8d08f18a Kostas Papadimitriou
            return n<10 ? '0'+n : n
158 8d08f18a Kostas Papadimitriou
        }
159 8d08f18a Kostas Papadimitriou
         return d.getUTCFullYear()+'-'
160 8d08f18a Kostas Papadimitriou
         + pad(d.getUTCMonth()+1)+'-'
161 8d08f18a Kostas Papadimitriou
         + pad(d.getUTCDate())+'T'
162 8d08f18a Kostas Papadimitriou
         + pad(d.getUTCHours())+':'
163 8d08f18a Kostas Papadimitriou
         + pad(d.getUTCMinutes())+':'
164 8d08f18a Kostas Papadimitriou
         + pad(d.getUTCSeconds())+'Z'
165 8d08f18a Kostas Papadimitriou
    }
166 8d08f18a Kostas Papadimitriou
167 258235f4 Kostas Papadimitriou
    
168 258235f4 Kostas Papadimitriou
    synnefo.util.parseHeaders = function(headers) {
169 258235f4 Kostas Papadimitriou
        var res = {};
170 258235f4 Kostas Papadimitriou
        _.each(headers.split("\n"), function(h) {
171 258235f4 Kostas Papadimitriou
            var tuple = h.split(/:(.+)?/);
172 258235f4 Kostas Papadimitriou
            if (!tuple.length > 1 || !(tuple[0] && tuple[1])) {
173 258235f4 Kostas Papadimitriou
                return;
174 258235f4 Kostas Papadimitriou
            }
175 258235f4 Kostas Papadimitriou
            res[tuple[0]] = tuple[1]
176 258235f4 Kostas Papadimitriou
        })
177 258235f4 Kostas Papadimitriou
178 258235f4 Kostas Papadimitriou
        return res;
179 258235f4 Kostas Papadimitriou
    }
180 258235f4 Kostas Papadimitriou
181 8d08f18a Kostas Papadimitriou
    synnefo.util.parseUri = function(sourceUri) {
182 8d08f18a Kostas Papadimitriou
        var uriPartNames = ["source","protocol","authority","domain","port","path","directoryPath","fileName","query","anchor"];
183 8d08f18a Kostas Papadimitriou
        var uriParts = new RegExp("^(?:([^:/?#.]+):)?(?://)?(([^:/?#]*)(?::(\\d*))?)?((/(?:[^?#](?![^?#/]*\\.[^?#/.]+(?:[\\?#]|$)))*/?)?([^?#/]*))?(?:\\?([^#]*))?(?:#(.*))?").exec(sourceUri);
184 8d08f18a Kostas Papadimitriou
        var uri = {};
185 8d08f18a Kostas Papadimitriou
        
186 8d08f18a Kostas Papadimitriou
        for(var i = 0; i < 10; i++){
187 8d08f18a Kostas Papadimitriou
            uri[uriPartNames[i]] = (uriParts[i] ? uriParts[i] : "");
188 8d08f18a Kostas Papadimitriou
        }
189 8d08f18a Kostas Papadimitriou
    
190 8d08f18a Kostas Papadimitriou
        // Always end directoryPath with a trailing backslash if a path was present in the source URI
191 8d08f18a Kostas Papadimitriou
        // Note that a trailing backslash is NOT automatically inserted within or appended to the "path" key
192 8d08f18a Kostas Papadimitriou
        if(uri.directoryPath.length > 0){
193 8d08f18a Kostas Papadimitriou
            uri.directoryPath = uri.directoryPath.replace(/\/?$/, "/");
194 8d08f18a Kostas Papadimitriou
        }
195 8d08f18a Kostas Papadimitriou
        
196 8d08f18a Kostas Papadimitriou
        return uri;
197 8d08f18a Kostas Papadimitriou
    }
198 8d08f18a Kostas Papadimitriou
199 820ef2f0 Kostas Papadimitriou
    synnefo.util.equalHeights = function() {
200 820ef2f0 Kostas Papadimitriou
        var max_height = 0;
201 820ef2f0 Kostas Papadimitriou
        var selectors = _.toArray(arguments);
202 73e25ce2 Kostas Papadimitriou
            
203 73e25ce2 Kostas Papadimitriou
        _.each(selectors, function(s){
204 73e25ce2 Kostas Papadimitriou
            console.log($(s).height());
205 73e25ce2 Kostas Papadimitriou
        })
206 820ef2f0 Kostas Papadimitriou
        // TODO: implement me
207 820ef2f0 Kostas Papadimitriou
    }
208 820ef2f0 Kostas Papadimitriou
209 35584d80 Kostas Papadimitriou
    synnefo.util.ClipHelper = function(wrapper, text, settings) {
210 35584d80 Kostas Papadimitriou
        settings = settings || {};
211 35584d80 Kostas Papadimitriou
        this.el = $('<div class="clip-copy"></div>');
212 35584d80 Kostas Papadimitriou
        wrapper.append(this.el);
213 35584d80 Kostas Papadimitriou
        this.clip = $(this.el).zclip(_.extend({
214 35584d80 Kostas Papadimitriou
            path: synnefo.config.js_url + "lib/ZeroClipboard.swf",
215 35584d80 Kostas Papadimitriou
            copy: text
216 35584d80 Kostas Papadimitriou
        }, settings));
217 49772990 Kostas Papadimitriou
    }
218 49772990 Kostas Papadimitriou
219 8d08f18a Kostas Papadimitriou
    synnefo.util.truncate = function(string, size, append, words) {
220 85b48c69 Kostas Papadimitriou
        if (string === undefined) { return "" };
221 8d08f18a Kostas Papadimitriou
        if (string.length <= size) {
222 8d08f18a Kostas Papadimitriou
            return string;
223 8d08f18a Kostas Papadimitriou
        }
224 8d08f18a Kostas Papadimitriou
225 8d08f18a Kostas Papadimitriou
        if (append === undefined) {
226 8d08f18a Kostas Papadimitriou
            append = "...";
227 8d08f18a Kostas Papadimitriou
        }
228 8d08f18a Kostas Papadimitriou
        
229 8d08f18a Kostas Papadimitriou
        if (!append) { append = "" };
230 8d08f18a Kostas Papadimitriou
        // TODO: implement word truncate
231 8d08f18a Kostas Papadimitriou
        if (words === undefined) {
232 8d08f18a Kostas Papadimitriou
            words = false;
233 8d08f18a Kostas Papadimitriou
        }
234 8d08f18a Kostas Papadimitriou
        
235 8d08f18a Kostas Papadimitriou
        len = size - append.length;
236 8d08f18a Kostas Papadimitriou
        return string.substring(0, len) + append;
237 8d08f18a Kostas Papadimitriou
    }
238 8d08f18a Kostas Papadimitriou
239 6653db48 Kostas Papadimitriou
    synnefo.util.readablizeBytes = function(bytes, fix) {
240 6653db48 Kostas Papadimitriou
        if (fix === undefined) { fix = 2; }
241 8d08f18a Kostas Papadimitriou
        var s = ['bytes', 'kb', 'MB', 'GB', 'TB', 'PB'];
242 8d08f18a Kostas Papadimitriou
        var e = Math.floor(Math.log(bytes)/Math.log(1024));
243 6653db48 Kostas Papadimitriou
        return (bytes/Math.pow(1024, Math.floor(e))).toFixed(fix)+" "+s[e];
244 8d08f18a Kostas Papadimitriou
    }
245 8d08f18a Kostas Papadimitriou
    
246 126a01f2 Kostas Papadimitriou
247 126a01f2 Kostas Papadimitriou
    synnefo.util.IP_REGEX = /(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/([0-9]|[1-2][0-9]|3[0-2]?)$/
248 126a01f2 Kostas Papadimitriou
249 8d08f18a Kostas Papadimitriou
    synnefo.i18n.API_ERROR_MESSAGES = {
250 8d08f18a Kostas Papadimitriou
        'timeout': {
251 b15a0cc4 Kostas Papadimitriou
            'message': 'TIMEOUT', 
252 b15a0cc4 Kostas Papadimitriou
            'allow_report': false,
253 b15a0cc4 Kostas Papadimitriou
            'type': 'Network'
254 8d08f18a Kostas Papadimitriou
        },
255 8d08f18a Kostas Papadimitriou
        
256 8d08f18a Kostas Papadimitriou
        'error': {
257 8d08f18a Kostas Papadimitriou
            'message': 'API error'
258 8d08f18a Kostas Papadimitriou
        }, 
259 8d08f18a Kostas Papadimitriou
260 8d08f18a Kostas Papadimitriou
        'abort': {},
261 9ce969a7 Kostas Papadimitriou
        'parserror': {},
262 9ce969a7 Kostas Papadimitriou
        '413': {
263 9ce969a7 Kostas Papadimitriou
            'title': "Account warning"
264 9ce969a7 Kostas Papadimitriou
        }
265 8d08f18a Kostas Papadimitriou
    }
266 8d08f18a Kostas Papadimitriou
    
267 8d08f18a Kostas Papadimitriou
    synnefo.util.array_diff = function(arr1, arr2) {
268 8d08f18a Kostas Papadimitriou
        var removed = [];
269 8d08f18a Kostas Papadimitriou
        var added = [];
270 8d08f18a Kostas Papadimitriou
271 8d08f18a Kostas Papadimitriou
        _.each(arr1, function(v) {
272 8d08f18a Kostas Papadimitriou
            if (arr2.indexOf(v) == -1) {
273 8d08f18a Kostas Papadimitriou
                removed[removed.length] = v;
274 8d08f18a Kostas Papadimitriou
            }
275 8d08f18a Kostas Papadimitriou
        })
276 8d08f18a Kostas Papadimitriou
277 8d08f18a Kostas Papadimitriou
278 8d08f18a Kostas Papadimitriou
        _.each(arr2, function(v) {
279 8d08f18a Kostas Papadimitriou
            if (arr1.indexOf(v) == -1) {
280 8d08f18a Kostas Papadimitriou
                added[added.length] = v;
281 8d08f18a Kostas Papadimitriou
            }
282 8d08f18a Kostas Papadimitriou
        })
283 8d08f18a Kostas Papadimitriou
284 8d08f18a Kostas Papadimitriou
        return {del: removed, add: added};
285 8d08f18a Kostas Papadimitriou
    }
286 8d08f18a Kostas Papadimitriou
287 a0839230 Kostas Papadimitriou
    synnefo.util.open_window = function(url, name, opts) {
288 8d08f18a Kostas Papadimitriou
        // default specs
289 a0839230 Kostas Papadimitriou
        opts = _.extend({
290 8d08f18a Kostas Papadimitriou
            menubar: 'no',
291 8d08f18a Kostas Papadimitriou
            toolbar: 'no',
292 8d08f18a Kostas Papadimitriou
            status: 'no',
293 8d08f18a Kostas Papadimitriou
            height: screen.height,
294 8d08f18a Kostas Papadimitriou
            width: screen.width,
295 8d08f18a Kostas Papadimitriou
            fullscreen: 'yes',
296 8d08f18a Kostas Papadimitriou
            channelmode: 'yes',
297 8d08f18a Kostas Papadimitriou
            directories: 'no',
298 8d08f18a Kostas Papadimitriou
            left: 0,
299 8d08f18a Kostas Papadimitriou
            location: 'no',
300 8d08f18a Kostas Papadimitriou
            top: 0
301 8d08f18a Kostas Papadimitriou
        }, opts)
302 8d08f18a Kostas Papadimitriou
        
303 a0839230 Kostas Papadimitriou
        var specs = _.map(opts, function(v,k) {return k + "=" + v}).join(",");
304 a0839230 Kostas Papadimitriou
        window.open(url, name, specs);
305 8d08f18a Kostas Papadimitriou
    }
306 2293458c Kostas Papadimitriou
    
307 2293458c Kostas Papadimitriou
    synnefo.util.readFileContents = function(f, cb) {
308 2293458c Kostas Papadimitriou
        var reader = new FileReader();
309 2293458c Kostas Papadimitriou
        var start = 0;
310 2293458c Kostas Papadimitriou
        var stop = f.size - 1;
311 2293458c Kostas Papadimitriou
312 2293458c Kostas Papadimitriou
        reader.onloadend = function(e) {
313 2293458c Kostas Papadimitriou
            return cb(e.target.result);
314 2293458c Kostas Papadimitriou
        }
315 2293458c Kostas Papadimitriou
        
316 2293458c Kostas Papadimitriou
        var data = reader.readAsText(f);
317 2293458c Kostas Papadimitriou
    },
318 2293458c Kostas Papadimitriou
    
319 2293458c Kostas Papadimitriou
    synnefo.util.generateKey = function(passphrase, length) {
320 2293458c Kostas Papadimitriou
        var passphrase = passphrase || "";
321 2293458c Kostas Papadimitriou
        var length = length || 1024;
322 2293458c Kostas Papadimitriou
        var key = cryptico.generateRSAKey(passphrase, length);
323 2293458c Kostas Papadimitriou
324 2293458c Kostas Papadimitriou
        _.extend(key.prototype, {
325 2293458c Kostas Papadimitriou
            download: function() {
326 2293458c Kostas Papadimitriou
            }
327 2293458c Kostas Papadimitriou
        });
328 2293458c Kostas Papadimitriou
329 2293458c Kostas Papadimitriou
        return key;
330 2293458c Kostas Papadimitriou
    }
331 2293458c Kostas Papadimitriou
    
332 2293458c Kostas Papadimitriou
    synnefo.util.publicKeyTypesMap = {
333 2293458c Kostas Papadimitriou
        "ecdsa-sha2-nistp256": "ecdsa",
334 2293458c Kostas Papadimitriou
        "ssh-dss" : "dsa",
335 2293458c Kostas Papadimitriou
        "ssh-rsa": "rsa"
336 2293458c Kostas Papadimitriou
    }
337 2293458c Kostas Papadimitriou
338 2293458c Kostas Papadimitriou
    synnefo.util.validatePublicKey = function(key) {
339 2293458c Kostas Papadimitriou
        var b64 = _(key).trim().split("\n").join("").split("\r\n").join("");
340 2293458c Kostas Papadimitriou
        var type = "rsa";
341 2293458c Kostas Papadimitriou
342 2293458c Kostas Papadimitriou
        // in case key starts with something like ssh-rsa
343 2293458c Kostas Papadimitriou
        if (b64.split(" ").length > 1) {
344 2293458c Kostas Papadimitriou
            var parts = key.split(" ");
345 2293458c Kostas Papadimitriou
            
346 2293458c Kostas Papadimitriou
            // identify key type
347 2293458c Kostas Papadimitriou
            type_key = parts[0];
348 2293458c Kostas Papadimitriou
            if (parseInt(type_key) >= 768) {
349 2293458c Kostas Papadimitriou
                type = "rsa1";
350 2293458c Kostas Papadimitriou
                
351 2293458c Kostas Papadimitriou
                if (parts[1] == 65537) {
352 2293458c Kostas Papadimitriou
                    if (parts.length == 3) {
353 2293458c Kostas Papadimitriou
                        return [parts[0], parts[1], parts[2]].join(" ")
354 2293458c Kostas Papadimitriou
                    }
355 2293458c Kostas Papadimitriou
                }
356 2293458c Kostas Papadimitriou
                // invalid rsa1 key
357 2293458c Kostas Papadimitriou
                throw "Invalid rsa1 key";
358 2293458c Kostas Papadimitriou
            }
359 2293458c Kostas Papadimitriou
            
360 2293458c Kostas Papadimitriou
            b64 = parts[1];
361 2293458c Kostas Papadimitriou
            if (!synnefo.util.publicKeyTypesMap[type_key]) { throw "Invalid rsa key (cannot identify encryption)" }
362 2293458c Kostas Papadimitriou
363 2293458c Kostas Papadimitriou
            try {
364 2293458c Kostas Papadimitriou
                var data = $.base64.decode(b64);
365 2293458c Kostas Papadimitriou
                return [parts[0], parts[1]].join(" ");
366 2293458c Kostas Papadimitriou
            } catch (err) {
367 2293458c Kostas Papadimitriou
                throw "Invalid key content";
368 2293458c Kostas Papadimitriou
            }
369 2293458c Kostas Papadimitriou
370 2293458c Kostas Papadimitriou
            throw "Invalid key content";
371 2293458c Kostas Papadimitriou
        }
372 2293458c Kostas Papadimitriou
        
373 2293458c Kostas Papadimitriou
        // no type defined check rsa
374 2293458c Kostas Papadimitriou
        if (_(b64).startsWith("AAAAB3NzaC1yc2EA")) {
375 2293458c Kostas Papadimitriou
            try {
376 2293458c Kostas Papadimitriou
                var data = $.base64.decode(b64);
377 2293458c Kostas Papadimitriou
                return ["ssh-rsa", b64].join(" ");
378 2293458c Kostas Papadimitriou
            } catch (err) {
379 2293458c Kostas Papadimitriou
                throw "Invalid content for rsa key";
380 2293458c Kostas Papadimitriou
            }
381 2293458c Kostas Papadimitriou
        }
382 2293458c Kostas Papadimitriou
383 2293458c Kostas Papadimitriou
        if (_(b64).startsWith("AAAAE2Vj")) {
384 2293458c Kostas Papadimitriou
            try {
385 2293458c Kostas Papadimitriou
                var data = $.base64.decode(b64);
386 2293458c Kostas Papadimitriou
                return ["ecdsa-sha2-nistp256", b64].join(" ");
387 2293458c Kostas Papadimitriou
            } catch (err) {
388 2293458c Kostas Papadimitriou
                throw "Invalid content for ecdsa key";
389 2293458c Kostas Papadimitriou
            }
390 2293458c Kostas Papadimitriou
        }
391 2293458c Kostas Papadimitriou
392 2293458c Kostas Papadimitriou
        if (_(b64).startsWith("AAAAB3N")) {
393 2293458c Kostas Papadimitriou
            try {
394 2293458c Kostas Papadimitriou
                var data = $.base64.decode(b64);
395 2293458c Kostas Papadimitriou
                return ["ssh-dss", b64].join(" ");
396 2293458c Kostas Papadimitriou
            } catch (err) {
397 2293458c Kostas Papadimitriou
                throw "Invalid content for dss key (" + err + ")";
398 2293458c Kostas Papadimitriou
            }
399 2293458c Kostas Papadimitriou
        }
400 2293458c Kostas Papadimitriou
401 2293458c Kostas Papadimitriou
        throw "Invalid key content";
402 2293458c Kostas Papadimitriou
    }
403 2293458c Kostas Papadimitriou
    
404 2293458c Kostas Papadimitriou
    // detect flash `like a boss`
405 2293458c Kostas Papadimitriou
    // http://stackoverflow.com/questions/998245/how-can-i-detect-if-flash-is-installed-and-if-not-display-a-hidden-div-that-inf/3336320#3336320 
406 2293458c Kostas Papadimitriou
    synnefo.util.hasFlash = function() {
407 2293458c Kostas Papadimitriou
        var hasFlash = false;
408 2293458c Kostas Papadimitriou
        try {
409 2293458c Kostas Papadimitriou
            var fo = new ActiveXObject('ShockwaveFlash.ShockwaveFlash');
410 2293458c Kostas Papadimitriou
            if (fo) hasFlash = true;
411 2293458c Kostas Papadimitriou
        } catch(e) {
412 2293458c Kostas Papadimitriou
          if(navigator.mimeTypes ["application/x-shockwave-flash"] != undefined) hasFlash = true;
413 2293458c Kostas Papadimitriou
        }
414 2293458c Kostas Papadimitriou
        return hasFlash;
415 2293458c Kostas Papadimitriou
    }
416 2293458c Kostas Papadimitriou
417 2293458c Kostas Papadimitriou
    synnefo.util.promptSaveFile = function(selector, filename, data, options) {
418 2293458c Kostas Papadimitriou
        if (!synnefo.util.hasFlash()) { return };
419 2293458c Kostas Papadimitriou
        try {
420 2293458c Kostas Papadimitriou
            return $(selector).downloadify(_.extend({
421 2293458c Kostas Papadimitriou
                filename: function(){ return filename },
422 2293458c Kostas Papadimitriou
                data: function(){ return data },
423 2293458c Kostas Papadimitriou
                onComplete: function(){},
424 2293458c Kostas Papadimitriou
                onCancel: function(){},
425 2293458c Kostas Papadimitriou
                onError: function(){
426 2293458c Kostas Papadimitriou
                    console.log("ERROR", arguments);
427 2293458c Kostas Papadimitriou
                },
428 2293458c Kostas Papadimitriou
                swf: synnefo.config.media_url + 'js/lib/media/downloadify.swf',
429 2293458c Kostas Papadimitriou
                downloadImage: synnefo.config.images_url + 'download.png',
430 2293458c Kostas Papadimitriou
                transparent: true,
431 2293458c Kostas Papadimitriou
                append: false,
432 2293458c Kostas Papadimitriou
                height:20,
433 2293458c Kostas Papadimitriou
                width: 20,
434 2293458c Kostas Papadimitriou
                dataType: 'string'
435 2293458c Kostas Papadimitriou
          }, options));
436 2293458c Kostas Papadimitriou
        } catch (err) {
437 2293458c Kostas Papadimitriou
            return false;
438 2293458c Kostas Papadimitriou
        }
439 2293458c Kostas Papadimitriou
    }
440 2293458c Kostas Papadimitriou
441 2293458c Kostas Papadimitriou
    synnefo.util.canReadFile = function() {
442 2293458c Kostas Papadimitriou
        if ($.browser.msie) { return false };
443 2293458c Kostas Papadimitriou
        if (window.FileReader && window.File) {
444 2293458c Kostas Papadimitriou
            var f = File.prototype.__proto__;
445 2293458c Kostas Papadimitriou
            if (f.slice || f.webkitSlice || f.mozSlice) {
446 2293458c Kostas Papadimitriou
                return true
447 2293458c Kostas Papadimitriou
            }
448 2293458c Kostas Papadimitriou
        }
449 2293458c Kostas Papadimitriou
        return false;
450 2293458c Kostas Papadimitriou
    }
451 2293458c Kostas Papadimitriou
452 2293458c Kostas Papadimitriou
    synnefo.util.errorList = function() {
453 2293458c Kostas Papadimitriou
        
454 2293458c Kostas Papadimitriou
        this.initialize = function() {
455 2293458c Kostas Papadimitriou
            this.errors = {};
456 2293458c Kostas Papadimitriou
        }
457 2293458c Kostas Papadimitriou
458 2293458c Kostas Papadimitriou
        this.add = function(key, msg) {
459 2293458c Kostas Papadimitriou
            this.errors[key] = this.errors[key] || [];
460 2293458c Kostas Papadimitriou
            this.errors[key].push(msg);
461 2293458c Kostas Papadimitriou
        }
462 2293458c Kostas Papadimitriou
463 2293458c Kostas Papadimitriou
        this.get = function(key) {
464 2293458c Kostas Papadimitriou
            return this.errors[key];
465 2293458c Kostas Papadimitriou
        }
466 2293458c Kostas Papadimitriou
467 2293458c Kostas Papadimitriou
        this.empty = function() {
468 2293458c Kostas Papadimitriou
            return _.isEmpty(this.errors);
469 2293458c Kostas Papadimitriou
        }
470 2293458c Kostas Papadimitriou
471 2293458c Kostas Papadimitriou
        this.initialize();
472 2293458c Kostas Papadimitriou
    }
473 8d08f18a Kostas Papadimitriou
474 8d08f18a Kostas Papadimitriou
    synnefo.util.stacktrace = function() {
475 8d08f18a Kostas Papadimitriou
        try {
476 8d08f18a Kostas Papadimitriou
            var obj = {};
477 8d08f18a Kostas Papadimitriou
            if (window.Error && Error.captureStackTrace) {
478 8d08f18a Kostas Papadimitriou
                Error.captureStackTrace(obj, synnefo.util.stacktrace);
479 8d08f18a Kostas Papadimitriou
                return obj.stack;
480 8d08f18a Kostas Papadimitriou
            } else {
481 8d08f18a Kostas Papadimitriou
                return printStackTrace().join("<br /><br />");
482 8d08f18a Kostas Papadimitriou
            }
483 8d08f18a Kostas Papadimitriou
        } catch (err) {}
484 8d08f18a Kostas Papadimitriou
        return "";
485 8d08f18a Kostas Papadimitriou
    },
486 820ef2f0 Kostas Papadimitriou
    
487 820ef2f0 Kostas Papadimitriou
    synnefo.util.array_combinations = function(arr) {
488 820ef2f0 Kostas Papadimitriou
        if (arr.length == 1) {
489 820ef2f0 Kostas Papadimitriou
            return arr[0];
490 820ef2f0 Kostas Papadimitriou
        } else {
491 820ef2f0 Kostas Papadimitriou
            var result = [];
492 820ef2f0 Kostas Papadimitriou
493 820ef2f0 Kostas Papadimitriou
            // recur with the rest of array
494 820ef2f0 Kostas Papadimitriou
            var allCasesOfRest = synnefo.util.array_combinations(arr.slice(1));  
495 820ef2f0 Kostas Papadimitriou
            for (var i = 0; i < allCasesOfRest.length; i++) {
496 820ef2f0 Kostas Papadimitriou
                for (var j = 0; j < arr[0].length; j++) {
497 820ef2f0 Kostas Papadimitriou
                    result.push(arr[0][j] + "-" + allCasesOfRest[i]);
498 820ef2f0 Kostas Papadimitriou
                }
499 820ef2f0 Kostas Papadimitriou
            }
500 820ef2f0 Kostas Papadimitriou
            return result;
501 820ef2f0 Kostas Papadimitriou
        }
502 820ef2f0 Kostas Papadimitriou
    }
503 8d08f18a Kostas Papadimitriou
504 9ce969a7 Kostas Papadimitriou
    synnefo.util.parse_api_error = function() {
505 9ce969a7 Kostas Papadimitriou
        if (arguments.length == 1) { arguments = arguments[0] };
506 8d08f18a Kostas Papadimitriou
507 8d08f18a Kostas Papadimitriou
        var xhr = arguments[0];
508 8d08f18a Kostas Papadimitriou
        var error_message = arguments[1];
509 8d08f18a Kostas Papadimitriou
        var error_thrown = arguments[2];
510 9ce969a7 Kostas Papadimitriou
        var ajax_settings = _.last(arguments) || {};
511 9ce969a7 Kostas Papadimitriou
        var call_settings = ajax_settings.error_params || {};
512 8d08f18a Kostas Papadimitriou
        var json_data = undefined;
513 9ce969a7 Kostas Papadimitriou
514 9ce969a7 Kostas Papadimitriou
        var critical = ajax_settings.critical === undefined ? true : ajax_settings.critical;
515 9ce969a7 Kostas Papadimitriou
516 8d08f18a Kostas Papadimitriou
        if (xhr.responseText) {
517 8d08f18a Kostas Papadimitriou
            try {
518 8d08f18a Kostas Papadimitriou
                json_data = JSON.parse(xhr.responseText)
519 1516800a Kostas Papadimitriou
            } catch (err) {
520 1516800a Kostas Papadimitriou
                json_data = 'Raw error response contnent (could not parse as JSON):\n\n' + xhr.responseText;
521 1516800a Kostas Papadimitriou
            }
522 8d08f18a Kostas Papadimitriou
        }
523 8d08f18a Kostas Papadimitriou
        
524 8d08f18a Kostas Papadimitriou
        module = "API"
525 8d08f18a Kostas Papadimitriou
526 8d08f18a Kostas Papadimitriou
        try {
527 8d08f18a Kostas Papadimitriou
            path = synnefo.util.parseUri(ajax_settings.url).path.split("/");
528 8d08f18a Kostas Papadimitriou
            path.splice(0,3)
529 8d08f18a Kostas Papadimitriou
            module = path.join("/");
530 8d08f18a Kostas Papadimitriou
        } catch (err) {
531 8d08f18a Kostas Papadimitriou
            console.error("cannot identify api error module");
532 8d08f18a Kostas Papadimitriou
        }
533 6a3a5bf7 Kostas Papadimitriou
        
534 8d08f18a Kostas Papadimitriou
        defaults = {
535 8d08f18a Kostas Papadimitriou
            'message': 'Api error',
536 8d08f18a Kostas Papadimitriou
            'type': 'API',
537 6a3a5bf7 Kostas Papadimitriou
            'allow_report': true,
538 9ce969a7 Kostas Papadimitriou
            'fatal_error': ajax_settings.critical || false,
539 9ce969a7 Kostas Papadimitriou
            'non_critical': !critical
540 8d08f18a Kostas Papadimitriou
        }
541 8d08f18a Kostas Papadimitriou
542 8d08f18a Kostas Papadimitriou
        var code = -1;
543 8d08f18a Kostas Papadimitriou
        try {
544 8d08f18a Kostas Papadimitriou
            code = xhr.status || "undefined";
545 8d08f18a Kostas Papadimitriou
        } catch (err) {console.error(err);}
546 8d08f18a Kostas Papadimitriou
        var details = "";
547 7f34b497 Kostas Papadimitriou
        
548 7f34b497 Kostas Papadimitriou
        if ([413].indexOf(code) > -1) {
549 7f34b497 Kostas Papadimitriou
            defaults.non_critical = true;
550 7f34b497 Kostas Papadimitriou
            defaults.allow_report = false;
551 7f34b497 Kostas Papadimitriou
            defaults.allow_reload = false;
552 9ce969a7 Kostas Papadimitriou
            error_message = "limit_error";
553 9ce969a7 Kostas Papadimitriou
        }
554 9ce969a7 Kostas Papadimitriou
555 9ce969a7 Kostas Papadimitriou
        if (critical) {
556 9ce969a7 Kostas Papadimitriou
            defaults.allow_report = true;
557 7f34b497 Kostas Papadimitriou
        }
558 8d08f18a Kostas Papadimitriou
        
559 8d08f18a Kostas Papadimitriou
        if (json_data) {
560 1516800a Kostas Papadimitriou
            if (_.isObject(json_data)) {
561 1516800a Kostas Papadimitriou
                $.each(json_data, function(key, obj) {
562 1516800a Kostas Papadimitriou
                    code = obj.code;
563 1516800a Kostas Papadimitriou
                    details = obj.details;
564 1516800a Kostas Papadimitriou
                    error_message = obj.message;
565 1516800a Kostas Papadimitriou
                })
566 1516800a Kostas Papadimitriou
            } else {
567 1516800a Kostas Papadimitriou
                details = json_data;
568 1516800a Kostas Papadimitriou
            }
569 8d08f18a Kostas Papadimitriou
        }
570 9ce969a7 Kostas Papadimitriou
571 8d08f18a Kostas Papadimitriou
        extra = {'URL': ajax_settings.url};
572 8d08f18a Kostas Papadimitriou
        options = {};
573 8d08f18a Kostas Papadimitriou
        options = _.extend(options, {'details': details, 'message': error_message, 'ns': module, 'extra_details': extra});
574 edd1d565 Kostas Papadimitriou
        options = _.extend(options, call_settings);
575 8d08f18a Kostas Papadimitriou
        options = _.extend(options, synnefo.i18n.API_ERROR_MESSAGES[error_message] || {});
576 9ce969a7 Kostas Papadimitriou
        options = _.extend(options, synnefo.i18n.API_ERROR_MESSAGES[code] || {});
577 b15a0cc4 Kostas Papadimitriou
        
578 b15a0cc4 Kostas Papadimitriou
        if (window.ERROR_OVERRIDES && window.ERROR_OVERRIDES[options.message]) {
579 b15a0cc4 Kostas Papadimitriou
            options.message = window.ERROR_OVERRIDES[options.message];
580 b15a0cc4 Kostas Papadimitriou
        }
581 73cb2274 Kostas Papadimitriou
        
582 73cb2274 Kostas Papadimitriou
        if (code && window.ERROR_OVERRIDES && window.ERROR_OVERRIDES[code]) {
583 b15a0cc4 Kostas Papadimitriou
            options.message = window.ERROR_OVERRIDES[code];
584 b15a0cc4 Kostas Papadimitriou
        }
585 b15a0cc4 Kostas Papadimitriou
586 8d08f18a Kostas Papadimitriou
        options = _.extend(defaults, options);
587 8d08f18a Kostas Papadimitriou
        options.code = code;
588 8d08f18a Kostas Papadimitriou
589 8d08f18a Kostas Papadimitriou
        return options;
590 8d08f18a Kostas Papadimitriou
    }
591 8d08f18a Kostas Papadimitriou
592 8d08f18a Kostas Papadimitriou
593 8d08f18a Kostas Papadimitriou
    // Backbone extensions
594 8d08f18a Kostas Papadimitriou
    //
595 8d08f18a Kostas Papadimitriou
    // super method
596 8d08f18a Kostas Papadimitriou
    Backbone.Model.prototype._super = Backbone.Collection.prototype._super = Backbone.View.prototype._super = function(funcName){
597 8d08f18a Kostas Papadimitriou
        return this.constructor.__super__[funcName].apply(this, _.rest(arguments));
598 8d08f18a Kostas Papadimitriou
    }
599 8d08f18a Kostas Papadimitriou
600 8d08f18a Kostas Papadimitriou
    // simple string format helper 
601 8d08f18a Kostas Papadimitriou
    // http://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format
602 8d08f18a Kostas Papadimitriou
    String.prototype.format = function() {
603 8d08f18a Kostas Papadimitriou
        var formatted = this;
604 8d08f18a Kostas Papadimitriou
        for (var i = 0; i < arguments.length; i++) {
605 8d08f18a Kostas Papadimitriou
            var regexp = new RegExp('\\{'+i+'\\}', 'gi');
606 8d08f18a Kostas Papadimitriou
            formatted = formatted.replace(regexp, arguments[i]);
607 8d08f18a Kostas Papadimitriou
        }
608 8d08f18a Kostas Papadimitriou
        return formatted;
609 8d08f18a Kostas Papadimitriou
    };
610 8d08f18a Kostas Papadimitriou
611 8d08f18a Kostas Papadimitriou
612 8d08f18a Kostas Papadimitriou
    $.fn.setCursorPosition = function(pos) {
613 8d08f18a Kostas Papadimitriou
        if ($(this).get(0).setSelectionRange) {
614 8d08f18a Kostas Papadimitriou
          $(this).get(0).setSelectionRange(pos, pos);
615 8d08f18a Kostas Papadimitriou
        } else if ($(this).get(0).createTextRange) {
616 8d08f18a Kostas Papadimitriou
          var range = $(this).get(0).createTextRange();
617 8d08f18a Kostas Papadimitriou
          range.collapse(true);
618 8d08f18a Kostas Papadimitriou
          range.moveEnd('character', pos);
619 8d08f18a Kostas Papadimitriou
          range.moveStart('character', pos);
620 8d08f18a Kostas Papadimitriou
          range.select();
621 8d08f18a Kostas Papadimitriou
        }
622 8d08f18a Kostas Papadimitriou
    }
623 73cb2274 Kostas Papadimitriou
624 73cb2274 Kostas Papadimitriou
    // trim prototype for IE
625 73cb2274 Kostas Papadimitriou
    if(typeof String.prototype.trim !== 'function') {
626 73cb2274 Kostas Papadimitriou
        String.prototype.trim = function() {
627 73cb2274 Kostas Papadimitriou
            return this.replace(/^\s+|\s+$/g, '');
628 73cb2274 Kostas Papadimitriou
        }
629 73cb2274 Kostas Papadimitriou
    }
630 73cb2274 Kostas Papadimitriou
631 73cb2274 Kostas Papadimitriou
    // http://stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area 
632 73cb2274 Kostas Papadimitriou
    $.fn.setCursorPosition = function(pos) {
633 675df0d2 Kostas Papadimitriou
        // not all browsers support setSelectionRange
634 675df0d2 Kostas Papadimitriou
        // put it in try/catch, fallback to no text selection
635 675df0d2 Kostas Papadimitriou
        try {
636 675df0d2 Kostas Papadimitriou
            if ($(this).get(0).setSelectionRange) {
637 675df0d2 Kostas Papadimitriou
              $(this).get(0).setSelectionRange(pos, pos);
638 675df0d2 Kostas Papadimitriou
            } else if ($(this).get(0).createTextRange) {
639 675df0d2 Kostas Papadimitriou
              var range = $(this).get(0).createTextRange();
640 675df0d2 Kostas Papadimitriou
              range.collapse(true);
641 675df0d2 Kostas Papadimitriou
              range.moveEnd('character', pos);
642 675df0d2 Kostas Papadimitriou
              range.moveStart('character', pos);
643 675df0d2 Kostas Papadimitriou
              range.select();
644 675df0d2 Kostas Papadimitriou
            }
645 675df0d2 Kostas Papadimitriou
        } catch (err) {
646 73cb2274 Kostas Papadimitriou
        }
647 73cb2274 Kostas Papadimitriou
    }
648 73cb2274 Kostas Papadimitriou
649 73cb2274 Kostas Papadimitriou
    // indexOf prototype for IE
650 73cb2274 Kostas Papadimitriou
    if (!Array.prototype.indexOf) {
651 73cb2274 Kostas Papadimitriou
      Array.prototype.indexOf = function(elt /*, from*/) {
652 73cb2274 Kostas Papadimitriou
        var len = this.length;
653 73cb2274 Kostas Papadimitriou
        var from = Number(arguments[1]) || 0;
654 73cb2274 Kostas Papadimitriou
        from = (from < 0)
655 73cb2274 Kostas Papadimitriou
             ? Math.ceil(from)
656 73cb2274 Kostas Papadimitriou
             : Math.floor(from);
657 73cb2274 Kostas Papadimitriou
        if (from < 0)
658 73cb2274 Kostas Papadimitriou
          from += len;
659 73cb2274 Kostas Papadimitriou
660 73cb2274 Kostas Papadimitriou
        for (; from < len; from++) {
661 73cb2274 Kostas Papadimitriou
          if (from in this &&
662 73cb2274 Kostas Papadimitriou
              this[from] === elt)
663 73cb2274 Kostas Papadimitriou
            return from;
664 73cb2274 Kostas Papadimitriou
        }
665 73cb2274 Kostas Papadimitriou
        return -1;
666 73cb2274 Kostas Papadimitriou
      };
667 73cb2274 Kostas Papadimitriou
    }
668 73cb2274 Kostas Papadimitriou
669 8d08f18a Kostas Papadimitriou
})(this);