Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | /* Any copyright is dedicated to the Public Domain. |
michael@0 | 2 | * http://creativecommons.org/publicdomain/zero/1.0/ |
michael@0 | 3 | */ |
michael@0 | 4 | |
michael@0 | 5 | /** |
michael@0 | 6 | * Helper functions for creating xml strings used by application update tests. |
michael@0 | 7 | * |
michael@0 | 8 | * !IMPORTANT - This file contains everything needed (along with dependencies) |
michael@0 | 9 | * by the updates.sjs file used by the mochitest-chrome tests. Since xpcshell |
michael@0 | 10 | * used by the http server is launched with -v 170 this file must not use |
michael@0 | 11 | * features greater than JavaScript 1.7. |
michael@0 | 12 | */ |
michael@0 | 13 | |
michael@0 | 14 | const FILE_SIMPLE_MAR = "simple.mar"; |
michael@0 | 15 | const SIZE_SIMPLE_MAR = "1031"; |
michael@0 | 16 | const MD5_HASH_SIMPLE_MAR = "1f8c038577bb6845d94ccec4999113ee"; |
michael@0 | 17 | const SHA1_HASH_SIMPLE_MAR = "5d49a672c87f10f31d7e326349564a11272a028b"; |
michael@0 | 18 | const SHA256_HASH_SIMPLE_MAR = "1aabbed5b1dd6e16e139afc5b43d479e254e0c26" + |
michael@0 | 19 | "3c8fb9249c0a1bb93071c5fb"; |
michael@0 | 20 | const SHA384_HASH_SIMPLE_MAR = "26615014ea034af32ef5651492d5f493f5a7a1a48522e" + |
michael@0 | 21 | "d24c366442a5ec21d5ef02e23fb58d79729b8ca2f9541" + |
michael@0 | 22 | "99dd53"; |
michael@0 | 23 | const SHA512_HASH_SIMPLE_MAR = "922e5ae22081795f6e8d65a3c508715c9a314054179a8" + |
michael@0 | 24 | "bbfe5f50dc23919ad89888291bc0a07586ab17dd0304a" + |
michael@0 | 25 | "b5347473601127571c66f61f5080348e05c36b"; |
michael@0 | 26 | |
michael@0 | 27 | const STATE_NONE = "null"; |
michael@0 | 28 | const STATE_DOWNLOADING = "downloading"; |
michael@0 | 29 | const STATE_PENDING = "pending"; |
michael@0 | 30 | const STATE_PENDING_SVC = "pending-service"; |
michael@0 | 31 | const STATE_APPLYING = "applying"; |
michael@0 | 32 | const STATE_APPLIED = "applied"; |
michael@0 | 33 | const STATE_APPLIED_SVC = "applied-service"; |
michael@0 | 34 | const STATE_SUCCEEDED = "succeeded"; |
michael@0 | 35 | const STATE_DOWNLOAD_FAILED = "download-failed"; |
michael@0 | 36 | const STATE_FAILED = "failed"; |
michael@0 | 37 | |
michael@0 | 38 | const STATE_FAILED_READ_ERROR = STATE_FAILED + ": 6"; |
michael@0 | 39 | const STATE_FAILED_WRITE_ERROR = STATE_FAILED + ": 7"; |
michael@0 | 40 | const STATE_FAILED_CHANNEL_MISMATCH_ERROR = STATE_FAILED + ": 22"; |
michael@0 | 41 | const STATE_FAILED_VERSION_DOWNGRADE_ERROR = STATE_FAILED + ": 23"; |
michael@0 | 42 | const STATE_FAILED_UNEXPECTED_FILE_OPERATION_ERROR = STATE_FAILED + ": 42"; |
michael@0 | 43 | |
michael@0 | 44 | /** |
michael@0 | 45 | * Constructs a string representing a remote update xml file. |
michael@0 | 46 | * |
michael@0 | 47 | * @param aUpdates |
michael@0 | 48 | * The string representing the update elements. |
michael@0 | 49 | * @return The string representing a remote update xml file. |
michael@0 | 50 | */ |
michael@0 | 51 | function getRemoteUpdatesXMLString(aUpdates) { |
michael@0 | 52 | return "<?xml version=\"1.0\"?>\n" + |
michael@0 | 53 | "<updates>\n" + |
michael@0 | 54 | aUpdates + |
michael@0 | 55 | "</updates>\n"; |
michael@0 | 56 | } |
michael@0 | 57 | |
michael@0 | 58 | /** |
michael@0 | 59 | * Constructs a string representing an update element for a remote update xml |
michael@0 | 60 | * file. See getUpdateString for parameter information not provided below. |
michael@0 | 61 | * |
michael@0 | 62 | * @param aPatches |
michael@0 | 63 | * String representing the application update patches. |
michael@0 | 64 | * @return The string representing an update element for an update xml file. |
michael@0 | 65 | */ |
michael@0 | 66 | function getRemoteUpdateString(aPatches, aType, aName, aDisplayVersion, |
michael@0 | 67 | aAppVersion, aPlatformVersion, aBuildID, |
michael@0 | 68 | aDetailsURL, aBillboardURL, aLicenseURL, |
michael@0 | 69 | aShowPrompt, aShowNeverForVersion, aPromptWaitTime, |
michael@0 | 70 | aShowSurvey, aVersion, aExtensionVersion, aCustom1, |
michael@0 | 71 | aCustom2) { |
michael@0 | 72 | return getUpdateString(aType, aName, aDisplayVersion, aAppVersion, |
michael@0 | 73 | aPlatformVersion, aBuildID, aDetailsURL, |
michael@0 | 74 | aBillboardURL, aLicenseURL, aShowPrompt, |
michael@0 | 75 | aShowNeverForVersion, aPromptWaitTime, aShowSurvey, |
michael@0 | 76 | aVersion, aExtensionVersion, aCustom1, aCustom2) + ">\n" + |
michael@0 | 77 | aPatches + |
michael@0 | 78 | " </update>\n"; |
michael@0 | 79 | } |
michael@0 | 80 | |
michael@0 | 81 | /** |
michael@0 | 82 | * Constructs a string representing a patch element for a remote update xml |
michael@0 | 83 | * file. See getPatchString for parameter information not provided below. |
michael@0 | 84 | * |
michael@0 | 85 | * @return The string representing a patch element for a remote update xml file. |
michael@0 | 86 | */ |
michael@0 | 87 | function getRemotePatchString(aType, aURL, aHashFunction, aHashValue, aSize) { |
michael@0 | 88 | return getPatchString(aType, aURL, aHashFunction, aHashValue, aSize) + |
michael@0 | 89 | "/>\n"; |
michael@0 | 90 | } |
michael@0 | 91 | |
michael@0 | 92 | /** |
michael@0 | 93 | * Constructs a string representing a local update xml file. |
michael@0 | 94 | * |
michael@0 | 95 | * @param aUpdates |
michael@0 | 96 | * The string representing the update elements. |
michael@0 | 97 | * @return The string representing a local update xml file. |
michael@0 | 98 | */ |
michael@0 | 99 | function getLocalUpdatesXMLString(aUpdates) { |
michael@0 | 100 | if (!aUpdates || aUpdates == "") |
michael@0 | 101 | return "<updates xmlns=\"http://www.mozilla.org/2005/app-update\"/>" |
michael@0 | 102 | return ("<updates xmlns=\"http://www.mozilla.org/2005/app-update\">" + |
michael@0 | 103 | aUpdates + |
michael@0 | 104 | "</updates>").replace(/>\s+\n*</g,'><'); |
michael@0 | 105 | } |
michael@0 | 106 | |
michael@0 | 107 | /** |
michael@0 | 108 | * Constructs a string representing an update element for a local update xml |
michael@0 | 109 | * file. See getUpdateString for parameter information not provided below. |
michael@0 | 110 | * |
michael@0 | 111 | * @param aPatches |
michael@0 | 112 | * String representing the application update patches. |
michael@0 | 113 | * @param aServiceURL (optional) |
michael@0 | 114 | * The update's xml url. |
michael@0 | 115 | * If not specified it will default to 'http://test_service/'. |
michael@0 | 116 | * @param aIsCompleteUpdate (optional) |
michael@0 | 117 | * The string 'true' if this update was a complete update or the string |
michael@0 | 118 | * 'false' if this update was a partial update. |
michael@0 | 119 | * If not specified it will default to 'true'. |
michael@0 | 120 | * @param aChannel (optional) |
michael@0 | 121 | * The update channel name. |
michael@0 | 122 | * If not specified it will default to the default preference value of |
michael@0 | 123 | * app.update.channel. |
michael@0 | 124 | * @param aForegroundDownload (optional) |
michael@0 | 125 | * The string 'true' if this update was manually downloaded or the |
michael@0 | 126 | * string 'false' if this update was automatically downloaded. |
michael@0 | 127 | * If not specified it will default to 'true'. |
michael@0 | 128 | * @param aPreviousAppVersion (optional) |
michael@0 | 129 | * The application version prior to applying the update. |
michael@0 | 130 | * If not specified it will not be present. |
michael@0 | 131 | * @return The string representing an update element for an update xml file. |
michael@0 | 132 | */ |
michael@0 | 133 | function getLocalUpdateString(aPatches, aType, aName, aDisplayVersion, |
michael@0 | 134 | aAppVersion, aPlatformVersion, aBuildID, |
michael@0 | 135 | aDetailsURL, aBillboardURL, aLicenseURL, |
michael@0 | 136 | aServiceURL, aInstallDate, aStatusText, |
michael@0 | 137 | aIsCompleteUpdate, aChannel, aForegroundDownload, |
michael@0 | 138 | aShowPrompt, aShowNeverForVersion, aPromptWaitTime, |
michael@0 | 139 | aShowSurvey, aVersion, aExtensionVersion, |
michael@0 | 140 | aPreviousAppVersion, aCustom1, aCustom2) { |
michael@0 | 141 | let serviceURL = aServiceURL ? aServiceURL : "http://test_service/"; |
michael@0 | 142 | let installDate = aInstallDate ? aInstallDate : "1238441400314"; |
michael@0 | 143 | let statusText = aStatusText ? aStatusText : "Install Pending"; |
michael@0 | 144 | let isCompleteUpdate = |
michael@0 | 145 | typeof(aIsCompleteUpdate) == "string" ? aIsCompleteUpdate : "true"; |
michael@0 | 146 | let channel = aChannel ? aChannel |
michael@0 | 147 | : gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); |
michael@0 | 148 | let foregroundDownload = |
michael@0 | 149 | typeof(aForegroundDownload) == "string" ? aForegroundDownload : "true"; |
michael@0 | 150 | let previousAppVersion = aPreviousAppVersion ? "previousAppVersion=\"" + |
michael@0 | 151 | aPreviousAppVersion + "\" " |
michael@0 | 152 | : ""; |
michael@0 | 153 | return getUpdateString(aType, aName, aDisplayVersion, aAppVersion, |
michael@0 | 154 | aPlatformVersion, aBuildID, aDetailsURL, aBillboardURL, |
michael@0 | 155 | aLicenseURL, aShowPrompt, aShowNeverForVersion, |
michael@0 | 156 | aPromptWaitTime, aShowSurvey, aVersion, aExtensionVersion, |
michael@0 | 157 | aCustom1, aCustom2) + |
michael@0 | 158 | " " + |
michael@0 | 159 | previousAppVersion + |
michael@0 | 160 | "serviceURL=\"" + serviceURL + "\" " + |
michael@0 | 161 | "installDate=\"" + installDate + "\" " + |
michael@0 | 162 | "statusText=\"" + statusText + "\" " + |
michael@0 | 163 | "isCompleteUpdate=\"" + isCompleteUpdate + "\" " + |
michael@0 | 164 | "channel=\"" + channel + "\" " + |
michael@0 | 165 | "foregroundDownload=\"" + foregroundDownload + "\">" + |
michael@0 | 166 | aPatches + |
michael@0 | 167 | " </update>"; |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | /** |
michael@0 | 171 | * Constructs a string representing a patch element for a local update xml file. |
michael@0 | 172 | * See getPatchString for parameter information not provided below. |
michael@0 | 173 | * |
michael@0 | 174 | * @param aSelected (optional) |
michael@0 | 175 | * Whether this patch is selected represented or not. The string 'true' |
michael@0 | 176 | * denotes selected and the string 'false' denotes not selected. |
michael@0 | 177 | * If not specified it will default to the string 'true'. |
michael@0 | 178 | * @param aState (optional) |
michael@0 | 179 | * The patch's state. |
michael@0 | 180 | * If not specified it will default to STATE_SUCCEEDED. |
michael@0 | 181 | * @return The string representing a patch element for a local update xml file. |
michael@0 | 182 | */ |
michael@0 | 183 | function getLocalPatchString(aType, aURL, aHashFunction, aHashValue, aSize, |
michael@0 | 184 | aSelected, aState) { |
michael@0 | 185 | let selected = typeof(aSelected) == "string" ? aSelected : "true"; |
michael@0 | 186 | let state = aState ? aState : STATE_SUCCEEDED; |
michael@0 | 187 | return getPatchString(aType, aURL, aHashFunction, aHashValue, aSize) + " " + |
michael@0 | 188 | "selected=\"" + selected + "\" " + |
michael@0 | 189 | "state=\"" + state + "\"/>\n"; |
michael@0 | 190 | } |
michael@0 | 191 | |
michael@0 | 192 | /** |
michael@0 | 193 | * Constructs a string representing an update element for a remote update xml |
michael@0 | 194 | * file. |
michael@0 | 195 | * |
michael@0 | 196 | * @param aType (optional) |
michael@0 | 197 | * The update's type which should be major or minor. If not specified it |
michael@0 | 198 | * will default to 'major'. |
michael@0 | 199 | * @param aName (optional) |
michael@0 | 200 | * The update's name. |
michael@0 | 201 | * If not specified it will default to 'App Update Test'. |
michael@0 | 202 | * @param aDisplayVersion (optional) |
michael@0 | 203 | * The update's display version. |
michael@0 | 204 | * If not specified it will default to 'version #' where # is the value |
michael@0 | 205 | * of DEFAULT_UPDATE_VERSION. |
michael@0 | 206 | * @param aAppVersion (optional) |
michael@0 | 207 | * The update's application version. |
michael@0 | 208 | * If not specified it will default to the value of |
michael@0 | 209 | * DEFAULT_UPDATE_VERSION. |
michael@0 | 210 | * @param aPlatformVersion (optional) |
michael@0 | 211 | * The update's platform version. |
michael@0 | 212 | * If not specified it will default to the value of |
michael@0 | 213 | * DEFAULT_UPDATE_VERSION. |
michael@0 | 214 | * @param aBuildID (optional) |
michael@0 | 215 | * The update's build id. |
michael@0 | 216 | * If not specified it will default to '20080811053724'. |
michael@0 | 217 | * @param aDetailsURL (optional) |
michael@0 | 218 | * The update's details url. |
michael@0 | 219 | * If not specified it will default to 'http://test_details/' due to due |
michael@0 | 220 | * to bug 470244. |
michael@0 | 221 | * @param aBillboardURL (optional) |
michael@0 | 222 | * The update's billboard url. |
michael@0 | 223 | * If not specified it will not be present. |
michael@0 | 224 | * @param aLicenseURL (optional) |
michael@0 | 225 | * The update's license url. |
michael@0 | 226 | * If not specified it will not be present. |
michael@0 | 227 | * @param aShowPrompt (optional) |
michael@0 | 228 | * Whether to show the prompt for the update when auto update is |
michael@0 | 229 | * enabled. |
michael@0 | 230 | * If not specified it will not be present and the update service will |
michael@0 | 231 | * default to false. |
michael@0 | 232 | * @param aShowNeverForVersion (optional) |
michael@0 | 233 | * Whether to show the 'No Thanks' button in the update prompt. |
michael@0 | 234 | * If not specified it will not be present and the update service will |
michael@0 | 235 | * default to false. |
michael@0 | 236 | * @param aPromptWaitTime (optional) |
michael@0 | 237 | * Override for the app.update.promptWaitTime preference. |
michael@0 | 238 | * @param aShowSurvey (optional) |
michael@0 | 239 | * Whether to show the 'No Thanks' button in the update prompt. |
michael@0 | 240 | * If not specified it will not be present and the update service will |
michael@0 | 241 | * default to false. |
michael@0 | 242 | * @param aVersion (optional) |
michael@0 | 243 | * The update's application version from 1.9.2. |
michael@0 | 244 | * If not specified it will not be present. |
michael@0 | 245 | * @param aExtensionVersion (optional) |
michael@0 | 246 | * The update's application version from 1.9.2. |
michael@0 | 247 | * If not specified it will not be present. |
michael@0 | 248 | * @param aCustom1 (optional) |
michael@0 | 249 | * A custom attribute name and attribute value to add to the xml. |
michael@0 | 250 | * Example: custom1_attribute="custom1 value" |
michael@0 | 251 | * If not specified it will not be present. |
michael@0 | 252 | * @param aCustom2 (optional) |
michael@0 | 253 | * A custom attribute name and attribute value to add to the xml. |
michael@0 | 254 | * Example: custom2_attribute="custom2 value" |
michael@0 | 255 | * If not specified it will not be present. |
michael@0 | 256 | * @return The string representing an update element for an update xml file. |
michael@0 | 257 | */ |
michael@0 | 258 | function getUpdateString(aType, aName, aDisplayVersion, aAppVersion, |
michael@0 | 259 | aPlatformVersion, aBuildID, aDetailsURL, aBillboardURL, |
michael@0 | 260 | aLicenseURL, aShowPrompt, aShowNeverForVersion, |
michael@0 | 261 | aPromptWaitTime, aShowSurvey, aVersion, aExtensionVersion, |
michael@0 | 262 | aCustom1, aCustom2) { |
michael@0 | 263 | let type = aType ? aType : "major"; |
michael@0 | 264 | let name = aName ? aName : "App Update Test"; |
michael@0 | 265 | let displayVersion = ""; |
michael@0 | 266 | if (aDisplayVersion || !aVersion) { |
michael@0 | 267 | displayVersion = "displayVersion=\"" + |
michael@0 | 268 | (aDisplayVersion ? aDisplayVersion |
michael@0 | 269 | : "version " + DEFAULT_UPDATE_VERSION) + |
michael@0 | 270 | "\" "; |
michael@0 | 271 | } |
michael@0 | 272 | // version has been deprecated in favor of displayVersion but it still needs |
michael@0 | 273 | // to be tested for forward compatibility. |
michael@0 | 274 | let version = aVersion ? "version=\"" + aVersion + "\" " : ""; |
michael@0 | 275 | let appVersion = ""; |
michael@0 | 276 | if (aAppVersion || !aExtensionVersion) { |
michael@0 | 277 | appVersion = "appVersion=\"" + |
michael@0 | 278 | (aAppVersion ? aAppVersion : DEFAULT_UPDATE_VERSION) + |
michael@0 | 279 | "\" "; |
michael@0 | 280 | } |
michael@0 | 281 | // extensionVersion has been deprecated in favor of appVersion but it still |
michael@0 | 282 | // needs to be tested for forward compatibility. |
michael@0 | 283 | let extensionVersion = aExtensionVersion ? "extensionVersion=\"" + |
michael@0 | 284 | aExtensionVersion + "\" " |
michael@0 | 285 | : ""; |
michael@0 | 286 | let platformVersion = ""; |
michael@0 | 287 | if (aPlatformVersion) { |
michael@0 | 288 | platformVersion = "platformVersion=\"" + |
michael@0 | 289 | (aPlatformVersion ? aPlatformVersion |
michael@0 | 290 | : DEFAULT_UPDATE_VERSION) + "\" "; |
michael@0 | 291 | } |
michael@0 | 292 | let buildID = aBuildID ? aBuildID : "20080811053724"; |
michael@0 | 293 | // XXXrstrong - not specifying a detailsURL will cause a leak due to bug 470244 |
michael@0 | 294 | // let detailsURL = aDetailsURL ? "detailsURL=\"" + aDetailsURL + "\" " : ""; |
michael@0 | 295 | let detailsURL = "detailsURL=\"" + |
michael@0 | 296 | (aDetailsURL ? aDetailsURL |
michael@0 | 297 | : "http://test_details/") + "\" "; |
michael@0 | 298 | let billboardURL = aBillboardURL ? "billboardURL=\"" + aBillboardURL + "\" " |
michael@0 | 299 | : ""; |
michael@0 | 300 | let licenseURL = aLicenseURL ? "licenseURL=\"" + aLicenseURL + "\" " : ""; |
michael@0 | 301 | let showPrompt = aShowPrompt ? "showPrompt=\"" + aShowPrompt + "\" " : ""; |
michael@0 | 302 | let showNeverForVersion = aShowNeverForVersion ? "showNeverForVersion=\"" + |
michael@0 | 303 | aShowNeverForVersion + "\" " |
michael@0 | 304 | : ""; |
michael@0 | 305 | let promptWaitTime = aPromptWaitTime ? "promptWaitTime=\"" + aPromptWaitTime + |
michael@0 | 306 | "\" " |
michael@0 | 307 | : ""; |
michael@0 | 308 | let custom1 = aCustom1 ? aCustom1 + " " : ""; |
michael@0 | 309 | let custom2 = aCustom2 ? aCustom2 + " " : ""; |
michael@0 | 310 | return " <update type=\"" + type + "\" " + |
michael@0 | 311 | "name=\"" + name + "\" " + |
michael@0 | 312 | displayVersion + |
michael@0 | 313 | version + |
michael@0 | 314 | appVersion + |
michael@0 | 315 | extensionVersion + |
michael@0 | 316 | platformVersion + |
michael@0 | 317 | detailsURL + |
michael@0 | 318 | billboardURL + |
michael@0 | 319 | licenseURL + |
michael@0 | 320 | showPrompt + |
michael@0 | 321 | showNeverForVersion + |
michael@0 | 322 | promptWaitTime + |
michael@0 | 323 | custom1 + |
michael@0 | 324 | custom2 + |
michael@0 | 325 | "buildID=\"" + buildID + "\""; |
michael@0 | 326 | } |
michael@0 | 327 | |
michael@0 | 328 | /** |
michael@0 | 329 | * Constructs a string representing a patch element for an update xml file. |
michael@0 | 330 | * |
michael@0 | 331 | * @param aType (optional) |
michael@0 | 332 | * The patch's type which should be complete or partial. |
michael@0 | 333 | * If not specified it will default to 'complete'. |
michael@0 | 334 | * @param aURL (optional) |
michael@0 | 335 | * The patch's url to the mar file. |
michael@0 | 336 | * If not specified it will default to the value of: |
michael@0 | 337 | * gURLData + FILE_SIMPLE_MAR |
michael@0 | 338 | * @param aHashFunction (optional) |
michael@0 | 339 | * The patch's hash function used to verify the mar file. |
michael@0 | 340 | * If not specified it will default to 'MD5'. |
michael@0 | 341 | * @param aHashValue (optional) |
michael@0 | 342 | * The patch's hash value used to verify the mar file. |
michael@0 | 343 | * If not specified it will default to the value of MD5_HASH_SIMPLE_MAR |
michael@0 | 344 | * which is the MD5 hash value for the file specified by FILE_SIMPLE_MAR. |
michael@0 | 345 | * @param aSize (optional) |
michael@0 | 346 | * The patch's file size for the mar file. |
michael@0 | 347 | * If not specified it will default to the file size for FILE_SIMPLE_MAR |
michael@0 | 348 | * specified by SIZE_SIMPLE_MAR. |
michael@0 | 349 | * @return The string representing a patch element for an update xml file. |
michael@0 | 350 | */ |
michael@0 | 351 | function getPatchString(aType, aURL, aHashFunction, aHashValue, aSize) { |
michael@0 | 352 | let type = aType ? aType : "complete"; |
michael@0 | 353 | let url = aURL ? aURL : gURLData + FILE_SIMPLE_MAR; |
michael@0 | 354 | let hashFunction = aHashFunction ? aHashFunction : "MD5"; |
michael@0 | 355 | let hashValue = aHashValue ? aHashValue : MD5_HASH_SIMPLE_MAR; |
michael@0 | 356 | let size = aSize ? aSize : SIZE_SIMPLE_MAR; |
michael@0 | 357 | return " <patch type=\"" + type + "\" " + |
michael@0 | 358 | "URL=\"" + url + "\" " + |
michael@0 | 359 | "hashFunction=\"" + hashFunction + "\" " + |
michael@0 | 360 | "hashValue=\"" + hashValue + "\" " + |
michael@0 | 361 | "size=\"" + size + "\""; |
michael@0 | 362 | } |