├── AUTHORS ├── .gitignore ├── tests ├── tests.js ├── node_tests.js ├── tests.html └── phantom.js ├── .travis.yml ├── README.md ├── package.json ├── queryString.js ├── main.js └── LICENSE /AUTHORS: -------------------------------------------------------------------------------- 1 | Eugene Lazutkin (http://lazutkin.com/) 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | *.iml 3 | .idea 4 | *.sublime-* 5 | report/* 6 | coverage/* 7 | -------------------------------------------------------------------------------- /tests/tests.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["module", "heya-unit"], function(module, unit){ 3 | "use strict"; 4 | 5 | // tests 6 | 7 | unit.add(module, [ 8 | ]); 9 | 10 | unit.run(); 11 | }); 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "0.6" 5 | - "0.8" 6 | - "0.10" 7 | 8 | env: 9 | - PHANTOM=true 10 | - PHANTOM=false 11 | 12 | matrix: 13 | exclude: 14 | - node_js: "0.6" 15 | env: PHANTOM=true 16 | - node_js: "0.8" 17 | env: PHANTOM=true 18 | 19 | before_script: if [ "$PHANTOM" == "true" ]; then export RUN_TEST="phantomjs tests/phantom.js"; else export RUN_TEST="npm test"; fi 20 | 21 | script: $RUN_TEST 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Form [![Build Status](https://travis-ci.org/heya/form.png?branch=master)](https://travis-ci.org/heya/form) 2 | 3 | Form: form-related utilities imported from Dojo. 4 | 5 | ## How to install 6 | 7 | If you plan to use it in your [node.js](http://nodejs.org) project install it 8 | like this: 9 | 10 | ``` 11 | npm install heya-form 12 | ``` 13 | 14 | For your browser-based projects I suggest to use [volo.js](http://volojs.org): 15 | 16 | ``` 17 | volo install heya/form heya-form 18 | ``` 19 | -------------------------------------------------------------------------------- /tests/node_tests.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | (["module", "heya-unit", "../queryString"], function(module, unit, qs){ 3 | "use strict"; 4 | 5 | // tests 6 | 7 | unit.add(module, [ 8 | function test_qs(t){ 9 | var t1 = {a: 1, b: "Hi!", c: [3, 5]}; 10 | //eval(t.TEST("qs.objectToQuery(t1) === 'a=1&b=Hi!&c=3&c=5'")); 11 | eval(t.TEST("t.unify(qs.queryToObject(qs.objectToQuery(t1)), {a: '1', b: 'Hi!', c: ['3', '5']})")); 12 | } 13 | ]); 14 | 15 | unit.run(); 16 | }); 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "heya-form", 3 | "version": "0.1.0", 4 | "description": "Form: form-related utilities imported from Dojo.", 5 | "main": "main.js", 6 | "directories": { 7 | "test": "tests" 8 | }, 9 | "dependencies": { 10 | "heya-dom": ">=0.1" 11 | }, 12 | "devDependencies": { 13 | "heya-unit": ">=0.1" 14 | }, 15 | "scripts": { 16 | "test": "node tests/node_tests.js" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git://github.com/heya/form.git" 21 | }, 22 | "keywords": [ 23 | "form", 24 | "DOM", 25 | "query string" 26 | ], 27 | "author": "Eugene Lazutkin (http://lazutkin.com/)", 28 | "license": "BSD" 29 | } 30 | -------------------------------------------------------------------------------- /tests/tests.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | heya-ctr test runner 5 | 6 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/phantom.js: -------------------------------------------------------------------------------- 1 | phantom.onError = function(msg, trace){ 2 | var msgStack = ["PHANTOM ERROR: " + msg]; 3 | if(trace){ 4 | msgStack.push("TRACE:"); 5 | trace.forEach(function(t){ 6 | msgStack.push(" -> " + (t.file || t.sourceURL) + ": " + t.line + 7 | (t.function ? " (in function " + t.function + ")" : "")); 8 | }); 9 | } 10 | console.error(msgStack.join('\n')); 11 | phantom.exit(1); 12 | }; 13 | 14 | var page = require("webpage").create(); 15 | 16 | page.onError = function(msg){ 17 | console.error("ERROR: " + msg); 18 | phantom.exit(1); 19 | }; 20 | 21 | page.onAlert = function(msg){ 22 | console.log("ALERT: " + msg); 23 | }; 24 | page.onConsoleMessage = function(msg){ 25 | console.log(msg); 26 | }; 27 | page.onCallback = function(msg){ 28 | switch(msg){ 29 | case "success": 30 | phantom.exit(0); 31 | break; 32 | case "failure": 33 | phantom.exit(1); 34 | break; 35 | } 36 | } 37 | 38 | var scriptPath = require("system").args[0], 39 | path = require("fs").absolute( 40 | (scriptPath.length && scriptPath.charAt(0) == "/" ? "" : "./") + scriptPath).split("/"); 41 | 42 | path.pop(); 43 | path.push("tests.html"); 44 | 45 | page.open(path.join("/"), function(status){ 46 | if(status !== "success"){ 47 | console.error("ERROR: Can't load a web page."); 48 | phantom.exit(1); 49 | } 50 | }); 51 | -------------------------------------------------------------------------------- /queryString.js: -------------------------------------------------------------------------------- 1 | /* UMD.define */ (typeof define=="function"&&define||function(d,f,m){m={module:module,require:require};module.exports=f.apply(null,d.map(function(n){return m[n]||require(n)}))}) 2 | ([], function(){ 3 | 4 | // module: 5 | // dojo/io-query 6 | 7 | var backstop = {}; 8 | 9 | return { 10 | // summary: 11 | // This module defines query string processing functions. 12 | 13 | objectToQuery: function objectToQuery(/*Object*/ map){ 14 | // summary: 15 | // takes a name/value mapping object and returns a string representing 16 | // a URL-encoded version of that object. 17 | // example: 18 | // this object: 19 | // 20 | // | { 21 | // | blah: "blah", 22 | // | multi: [ 23 | // | "thud", 24 | // | "thonk" 25 | // | ] 26 | // | }; 27 | // 28 | // yields the following query string: 29 | // 30 | // | "blah=blah&multi=thud&multi=thonk" 31 | 32 | // FIXME: need to implement encodeAscii!! 33 | var enc = encodeURIComponent, pairs = []; 34 | for(var name in map){ 35 | var value = map[name]; 36 | if(value != backstop[name]){ 37 | var assign = enc(name) + "="; 38 | if(value instanceof Array){ 39 | for(var i = 0, l = value.length; i < l; ++i){ 40 | pairs.push(assign + enc(value[i])); 41 | } 42 | }else{ 43 | pairs.push(assign + enc(value)); 44 | } 45 | } 46 | } 47 | return pairs.join("&"); // String 48 | }, 49 | 50 | queryToObject: function queryToObject(/*String*/ str){ 51 | // summary: 52 | // Create an object representing a de-serialized query section of a 53 | // URL. Query keys with multiple values are returned in an array. 54 | // 55 | // example: 56 | // This string: 57 | // 58 | // | "foo=bar&foo=baz&thinger=%20spaces%20=blah&zonk=blarg&" 59 | // 60 | // results in this object structure: 61 | // 62 | // | { 63 | // | foo: [ "bar", "baz" ], 64 | // | thinger: " spaces =blah", 65 | // | zonk: "blarg" 66 | // | } 67 | // 68 | // Note that spaces and other urlencoded entities are correctly 69 | // handled. 70 | 71 | // FIXME: should we grab the URL string if we're not passed one? 72 | var dec = decodeURIComponent, qp = str.split("&"), ret = {}, name, val; 73 | for(var i = 0, l = qp.length, item; i < l; ++i){ 74 | item = qp[i]; 75 | if(item.length){ 76 | var s = item.indexOf("="); 77 | if(s < 0){ 78 | name = dec(item); 79 | val = ""; 80 | }else{ 81 | name = dec(item.slice(0, s)); 82 | val = dec(item.slice(s + 1)); 83 | } 84 | if(typeof ret[name] == "string"){ // inline'd type check 85 | ret[name] = [ret[name]]; 86 | } 87 | 88 | if(ret[name] instanceof Array){ 89 | ret[name].push(val); 90 | }else{ 91 | ret[name] = val; 92 | } 93 | } 94 | } 95 | return ret; // Object 96 | } 97 | }; 98 | }); 99 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | define(["heya-dom", "./queryString"], function(dom, queryString){ 2 | // module: 3 | // dojo/dom-form 4 | 5 | function setValue(/*Object*/ obj, /*String*/ name, /*String*/ value){ 6 | // summary: 7 | // For the named property in object, set the value. If a value 8 | // already exists and it is a string, convert the value to be an 9 | // array of values. 10 | 11 | // Skip it if there is no value 12 | if(value === null){ 13 | return; 14 | } 15 | 16 | var val = obj[name]; 17 | if(typeof val == "string"){ // inline'd type check 18 | obj[name] = [val, value]; 19 | }else if(val instanceof Array){ 20 | val.push(value); 21 | }else{ 22 | obj[name] = value; 23 | } 24 | } 25 | 26 | var exclude = "file|submit|image|reset|button"; 27 | 28 | var module = { 29 | // summary: 30 | // This module defines form-processing functions. 31 | 32 | fieldToObject: function fieldToObject(/*DOMNode|String*/ inputNode){ 33 | // summary: 34 | // Serialize a form field to a JavaScript object. 35 | // description: 36 | // Returns the value encoded in a form field as 37 | // as a string or an array of strings. Disabled form elements 38 | // and unchecked radio and checkboxes are skipped. Multi-select 39 | // elements are returned as an array of string values. 40 | // inputNode: DOMNode|String 41 | // returns: Object 42 | 43 | var ret = null; 44 | inputNode = dom.byId(inputNode); 45 | if(inputNode){ 46 | var _in = inputNode.name, type = (inputNode.type || "").toLowerCase(); 47 | if(_in && type && !inputNode.disabled){ 48 | if(type == "radio" || type == "checkbox"){ 49 | if(inputNode.checked){ 50 | ret = inputNode.value; 51 | } 52 | }else if(inputNode.multiple){ 53 | ret = []; 54 | var nodes = [inputNode.firstChild]; 55 | while(nodes.length){ 56 | for(var node = nodes.pop(); node; node = node.nextSibling){ 57 | if(node.nodeType == 1 && node.tagName.toLowerCase() == "option"){ 58 | if(node.selected){ 59 | ret.push(node.value); 60 | } 61 | }else{ 62 | if(node.nextSibling){ 63 | nodes.push(node.nextSibling); 64 | } 65 | if(node.firstChild){ 66 | nodes.push(node.firstChild); 67 | } 68 | break; 69 | } 70 | } 71 | } 72 | }else{ 73 | ret = inputNode.value; 74 | } 75 | } 76 | } 77 | return ret; // Object 78 | }, 79 | 80 | toObject: function formToObject(/*DOMNode|String*/ formNode){ 81 | // summary: 82 | // Serialize a form node to a JavaScript object. 83 | // description: 84 | // Returns the values encoded in an HTML form as 85 | // string properties in an object which it then returns. Disabled form 86 | // elements, buttons, and other non-value form elements are skipped. 87 | // Multi-select elements are returned as an array of string values. 88 | // formNode: DOMNode|String 89 | // example: 90 | // This form: 91 | // |
92 | // | 93 | // | 94 | // | 95 | // | 100 | // |
101 | // 102 | // yields this object structure as the result of a call to 103 | // formToObject(): 104 | // 105 | // | { 106 | // | blah: "blah", 107 | // | multi: [ 108 | // | "thud", 109 | // | "thonk" 110 | // | ] 111 | // | }; 112 | 113 | var ret = {}, elems = dom.byId(formNode).elements; 114 | for(var i = 0, l = elems.length; i < l; ++i){ 115 | var item = elems[i], _in = item.name, type = (item.type || "").toLowerCase(); 116 | if(_in && type && exclude.indexOf(type) < 0 && !item.disabled){ 117 | setValue(ret, _in, module.fieldToObject(item)); 118 | if(type == "image"){ 119 | ret[_in + ".x"] = ret[_in + ".y"] = ret[_in].x = ret[_in].y = 0; 120 | } 121 | } 122 | } 123 | return ret; // Object 124 | }, 125 | 126 | toQuery: function formToQuery(/*DOMNode|String*/ formNode){ 127 | // summary: 128 | // Returns a URL-encoded string representing the form passed as either a 129 | // node or string ID identifying the form to serialize 130 | // formNode: DOMNode|String 131 | // returns: String 132 | 133 | return queryString.objectToQuery(module.toObject(formNode)); // String 134 | }, 135 | 136 | toJson: function formToJson(/*DOMNode|String*/ formNode, /*Boolean?*/ prettyPrint){ 137 | // summary: 138 | // Create a serialized JSON string from a form node or string 139 | // ID identifying the form to serialize 140 | // formNode: DOMNode|String 141 | // prettyPrint: Boolean? 142 | // returns: String 143 | 144 | return JSON.stringify(module.toObject(formNode), null, 145 | typeof prettyPrint == "number" ? prettyPrint : 146 | prettyPrint ? 4 : 0); // String 147 | } 148 | }; 149 | 150 | return module; 151 | }); 152 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This library is available under *either* the terms of the modified BSD license 2 | *or* the Academic Free License version 2.1. As a recipient of this work, you 3 | may choose which license to receive this code under. No external contributions 4 | are allowed under licenses which are fundamentally incompatible with the AFL 5 | or BSD licenses that this library is distributed under. 6 | 7 | The text of the AFL and BSD licenses is reproduced below. 8 | 9 | ------------------------------------------------------------------------------- 10 | The "New" BSD License: 11 | ********************** 12 | 13 | Copyright (c) 2005-2012, Eugene Lazutkin 14 | All rights reserved. 15 | 16 | Redistribution and use in source and binary forms, with or without 17 | modification, are permitted provided that the following conditions are met: 18 | 19 | * Redistributions of source code must retain the above copyright notice, this 20 | list of conditions and the following disclaimer. 21 | * Redistributions in binary form must reproduce the above copyright notice, 22 | this list of conditions and the following disclaimer in the documentation 23 | and/or other materials provided with the distribution. 24 | * Neither the name of Eugene Lazutkin nor the names of other contributors 25 | may be used to endorse or promote products derived from this software 26 | without specific prior written permission. 27 | 28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 29 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 30 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 32 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 34 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | 39 | ------------------------------------------------------------------------------- 40 | The Academic Free License, v. 2.1: 41 | ********************************** 42 | 43 | This Academic Free License (the "License") applies to any original work of 44 | authorship (the "Original Work") whose owner (the "Licensor") has placed the 45 | following notice immediately following the copyright notice for the Original 46 | Work: 47 | 48 | Licensed under the Academic Free License version 2.1 49 | 50 | 1) Grant of Copyright License. Licensor hereby grants You a world-wide, 51 | royalty-free, non-exclusive, perpetual, sublicenseable license to do the 52 | following: 53 | 54 | a) to reproduce the Original Work in copies; 55 | 56 | b) to prepare derivative works ("Derivative Works") based upon the Original 57 | Work; 58 | 59 | c) to distribute copies of the Original Work and Derivative Works to the 60 | public; 61 | 62 | d) to perform the Original Work publicly; and 63 | 64 | e) to display the Original Work publicly. 65 | 66 | 2) Grant of Patent License. Licensor hereby grants You a world-wide, 67 | royalty-free, non-exclusive, perpetual, sublicenseable license, under patent 68 | claims owned or controlled by the Licensor that are embodied in the Original 69 | Work as furnished by the Licensor, to make, use, sell and offer for sale the 70 | Original Work and Derivative Works. 71 | 72 | 3) Grant of Source Code License. The term "Source Code" means the preferred 73 | form of the Original Work for making modifications to it and all available 74 | documentation describing how to modify the Original Work. Licensor hereby 75 | agrees to provide a machine-readable copy of the Source Code of the Original 76 | Work along with each copy of the Original Work that Licensor distributes. 77 | Licensor reserves the right to satisfy this obligation by placing a 78 | machine-readable copy of the Source Code in an information repository 79 | reasonably calculated to permit inexpensive and convenient access by You for as 80 | long as Licensor continues to distribute the Original Work, and by publishing 81 | the address of that information repository in a notice immediately following 82 | the copyright notice that applies to the Original Work. 83 | 84 | 4) Exclusions From License Grant. Neither the names of Licensor, nor the names 85 | of any contributors to the Original Work, nor any of their trademarks or 86 | service marks, may be used to endorse or promote products derived from this 87 | Original Work without express prior written permission of the Licensor. Nothing 88 | in this License shall be deemed to grant any rights to trademarks, copyrights, 89 | patents, trade secrets or any other intellectual property of Licensor except as 90 | expressly stated herein. No patent license is granted to make, use, sell or 91 | offer to sell embodiments of any patent claims other than the licensed claims 92 | defined in Section 2. No right is granted to the trademarks of Licensor even if 93 | such marks are included in the Original Work. Nothing in this License shall be 94 | interpreted to prohibit Licensor from licensing under different terms from this 95 | License any Original Work that Licensor otherwise would have a right to 96 | license. 97 | 98 | 5) This section intentionally omitted. 99 | 100 | 6) Attribution Rights. You must retain, in the Source Code of any Derivative 101 | Works that You create, all copyright, patent or trademark notices from the 102 | Source Code of the Original Work, as well as any notices of licensing and any 103 | descriptive text identified therein as an "Attribution Notice." You must cause 104 | the Source Code for any Derivative Works that You create to carry a prominent 105 | Attribution Notice reasonably calculated to inform recipients that You have 106 | modified the Original Work. 107 | 108 | 7) Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that 109 | the copyright in and to the Original Work and the patent rights granted herein 110 | by Licensor are owned by the Licensor or are sublicensed to You under the terms 111 | of this License with the permission of the contributor(s) of those copyrights 112 | and patent rights. Except as expressly stated in the immediately proceeding 113 | sentence, the Original Work is provided under this License on an "AS IS" BASIS 114 | and WITHOUT WARRANTY, either express or implied, including, without limitation, 115 | the warranties of NON-INFRINGEMENT, MERCHANTABILITY or FITNESS FOR A PARTICULAR 116 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. 117 | This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No 118 | license to Original Work is granted hereunder except under this disclaimer. 119 | 120 | 8) Limitation of Liability. Under no circumstances and under no legal theory, 121 | whether in tort (including negligence), contract, or otherwise, shall the 122 | Licensor be liable to any person for any direct, indirect, special, incidental, 123 | or consequential damages of any character arising as a result of this License 124 | or the use of the Original Work including, without limitation, damages for loss 125 | of goodwill, work stoppage, computer failure or malfunction, or any and all 126 | other commercial damages or losses. This limitation of liability shall not 127 | apply to liability for death or personal injury resulting from Licensor's 128 | negligence to the extent applicable law prohibits such limitation. Some 129 | jurisdictions do not allow the exclusion or limitation of incidental or 130 | consequential damages, so this exclusion and limitation may not apply to You. 131 | 132 | 9) Acceptance and Termination. If You distribute copies of the Original Work or 133 | a Derivative Work, You must make a reasonable effort under the circumstances to 134 | obtain the express assent of recipients to the terms of this License. Nothing 135 | else but this License (or another written agreement between Licensor and You) 136 | grants You permission to create Derivative Works based upon the Original Work 137 | or to exercise any of the rights granted in Section 1 herein, and any attempt 138 | to do so except under the terms of this License (or another written agreement 139 | between Licensor and You) is expressly prohibited by U.S. copyright law, the 140 | equivalent laws of other countries, and by international treaty. Therefore, by 141 | exercising any of the rights granted to You in Section 1 herein, You indicate 142 | Your acceptance of this License and all of its terms and conditions. 143 | 144 | 10) Termination for Patent Action. This License shall terminate automatically 145 | and You may no longer exercise any of the rights granted to You by this License 146 | as of the date You commence an action, including a cross-claim or counterclaim, 147 | against Licensor or any licensee alleging that the Original Work infringes a 148 | patent. This termination provision shall not apply for an action alleging 149 | patent infringement by combinations of the Original Work with other software or 150 | hardware. 151 | 152 | 11) Jurisdiction, Venue and Governing Law. Any action or suit relating to this 153 | License may be brought only in the courts of a jurisdiction wherein the 154 | Licensor resides or in which Licensor conducts its primary business, and under 155 | the laws of that jurisdiction excluding its conflict-of-law provisions. The 156 | application of the United Nations Convention on Contracts for the International 157 | Sale of Goods is expressly excluded. Any use of the Original Work outside the 158 | scope of this License or after its termination shall be subject to the 159 | requirements and penalties of the U.S. Copyright Act, 17 U.S.C. § 101 et 160 | seq., the equivalent laws of other countries, and international treaty. This 161 | section shall survive the termination of this License. 162 | 163 | 12) Attorneys Fees. In any action to enforce the terms of this License or 164 | seeking damages relating thereto, the prevailing party shall be entitled to 165 | recover its costs and expenses, including, without limitation, reasonable 166 | attorneys' fees and costs incurred in connection with such action, including 167 | any appeal of such action. This section shall survive the termination of this 168 | License. 169 | 170 | 13) Miscellaneous. This License represents the complete agreement concerning 171 | the subject matter hereof. If any provision of this License is held to be 172 | unenforceable, such provision shall be reformed only to the extent necessary to 173 | make it enforceable. 174 | 175 | 14) Definition of "You" in This License. "You" throughout this License, whether 176 | in upper or lower case, means an individual or a legal entity exercising rights 177 | under, and complying with all of the terms of, this License. For legal 178 | entities, "You" includes any entity that controls, is controlled by, or is 179 | under common control with you. For purposes of this definition, "control" means 180 | (i) the power, direct or indirect, to cause the direction or management of such 181 | entity, whether by contract or otherwise, or (ii) ownership of fifty percent 182 | (50%) or more of the outstanding shares, or (iii) beneficial ownership of such 183 | entity. 184 | 185 | 15) Right to Use. You may use the Original Work in all ways not otherwise 186 | restricted or conditioned by this License or by law, and Licensor promises not 187 | to interfere with or be responsible for such uses by You. 188 | 189 | This license is Copyright (C) 2003-2004 Lawrence E. Rosen. All rights reserved. 190 | Permission is hereby granted to copy and distribute this license without 191 | modification. This license may not be modified without the express written 192 | permission of its copyright owner. 193 | --------------------------------------------------------------------------------