├── .scrutinizer.yml ├── examples ├── list-files.html ├── list-files - with page.html ├── get-info - example 1.html ├── list-files - in directory.html ├── list-files - with page and results per page.html ├── get-info - example 2.html ├── destroy-files.html └── schedule-files.html ├── sandcage.min.js ├── README.md ├── json2.min.js ├── sandcage.coffee ├── sandcage.js ├── LICENSE └── json2.js /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | excluded_paths: ["examples/*", "json2*", "*.min.js", "*.coffee"] 3 | checks: 4 | javascript: true 5 | build: true -------------------------------------------------------------------------------- /examples/list-files.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | If you have opened this page in a browser, open the console and reload the page for the output.
10 | For the documentation of the List Files service, click Here 11 | 18 | 19 | -------------------------------------------------------------------------------- /examples/list-files - with page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | If you have opened this page in a browser, open the console and reload the page for the output.
10 | For the documentation of the List Files service, click Here 11 | 20 | 21 | -------------------------------------------------------------------------------- /examples/get-info - example 1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | If you have opened this page in a browser, open the console and reload the page for the output.
10 | For the documentation of the Get Info service, click Here 11 | 20 | 21 | -------------------------------------------------------------------------------- /examples/list-files - in directory.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | If you have opened this page in a browser, open the console and reload the page for the output.
10 | For the documentation of the List Files service, click Here 11 | 20 | 21 | -------------------------------------------------------------------------------- /examples/list-files - with page and results per page.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | If you have opened this page in a browser, open the console and reload the page for the output.
10 | For the documentation of the List Files service, click Here 11 | 21 | 22 | -------------------------------------------------------------------------------- /examples/get-info - example 2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | If you have opened this page in a browser, open the console and reload the page for the output.
10 | For the documentation of the Get Info service, click Here 11 | 23 | 24 | -------------------------------------------------------------------------------- /examples/destroy-files.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | If you have opened this page in a browser, open the console and reload the page for the output.
10 | For the documentation of the Destroy Files service, click Here 11 | 24 | 25 | -------------------------------------------------------------------------------- /sandcage.min.js: -------------------------------------------------------------------------------- 1 | var SandCage;SandCage=function(){function e(e){return this.apikey=e,this.apikey?(t=this,("undefined"==typeof JSON||null===JSON)&&this.loadScript("json2.min.js"),this):{status:"error",name:"MissingKey",message:"Provide your SandCage API Key."}}var t={},n="0.2",r="https://api.sandcage.com/"+n+"/";return e.call=function(e,n,r,a){var s,i;if(null==n||n==={})return!1;i={key:t.apikey};for(s in n)i[s]=n[s];return this.ajaxCall(e,i,r,a)},e.ajaxCall=function(e,t,n,a){var s;return n||(t.callback_url=n),t=JSON.stringify(t),s=new XMLHttpRequest,s.open("POST",""+r+e,!1),s.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),s.onreadystatechange=function(){var e;return 4!==s.readyState?!1:(e=JSON.parse(s.responseText),null==e&&(e={status:"error",name:"GenericError",message:"An error occurred."}),a?a(e):!1)},s.send(t)},e.loadScript=function(e){var t;t=new XMLHttpRequest,t.open("GET",e,!1),t.onreadystatechange=function(){var n;4===t.readyState&&200===t.status&&(n=document.createElement("script"),n.setAttribute("type","text/javascript"),n.setAttribute("charset","UTF-8"),n.setAttribute("src",e),document.head.appendChild(n))},t.send(null)},e.getInfo=function(e,t){return null==t?!1:this.call("get-info",e,"",t)},e.listFiles=function(e,t){return null==t?!1:this.call("list-files",e,"",t)},e.scheduleFiles=function(e,t,n){return this.call("schedule-tasks",e,t,n)},e.destroyFiles=function(e,t,n){return this.call("destroy-files",e,t,n)},e}(); -------------------------------------------------------------------------------- /examples/schedule-files.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | If you have opened this page in a browser, open the console and reload the page for the output.
10 | For the documentation of the Schedule Tasks service, click Here 11 | 59 | 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![SandCage](https://d18m5nnl28b2pp.cloudfront.net/p/a/img/header.png) 2 | 3 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/sandcage/sandcage-api-js/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/sandcage/sandcage-api-js/?branch=master) 4 | [![Build Status](https://scrutinizer-ci.com/g/sandcage/sandcage-api-js/badges/build.png?b=master)](https://scrutinizer-ci.com/g/sandcage/sandcage-api-js/build-status/master) 5 | 6 | sandcage-api-js is a JavaScript library for interfacing with SandCage's API. The API documentation can be found at https://www.sandcage.com/docs/0.2/ 7 | 8 | 9 | ### Table of Contents 10 | * [Requirements](https://github.com/sandcage/sandcage-api-js/blob/master/README.md#requirements) 11 | * [Usage](https://github.com/sandcage/sandcage-api-js/blob/master/README.md#usage) 12 | * [Examples](https://github.com/sandcage/sandcage-api-js/tree/master/examples) 13 | * [Contributing](https://github.com/sandcage/sandcage-api-js/blob/master/README.md#contribute) 14 | * [Contact Us](https://www.sandcage.com/contact) 15 | 16 | 17 | 18 | ## Requirements 19 | 20 | * A SandCage account, in order to get your SandCage API Key. Once logged into SandCage get your API Key at https://www.sandcage.com/panel/api_key 21 | 22 | 23 | 24 | ## Usage 25 | 26 | ```javascript 27 | var sandcage = SandCage('[YOUR SANDCAGE API KEY]'); 28 | sandcage.SandCage.listFiles({}, function(resp) { 29 | console.log(resp); 30 | }) 31 | ``` 32 | 33 | 34 | 35 | ## Contributing 36 | 37 | We are open to suggestions and code revisions, however there are some rules and limitations that you might want to consider first. 38 | 39 | * Code that you contribute will automatically be licensed under the [Apache License Version 2.0](https://github.com/sandcage/sandcage-api-js/blob/master/LICENSE). 40 | * Third party code will be reviewed, tested and possibly modified before being released. 41 | 42 | These basic rules help ensure that this code remains Open Source and compatible with Apache 2.0 license. All contributions will be added to the changelog and appear in every release. -------------------------------------------------------------------------------- /json2.min.js: -------------------------------------------------------------------------------- 1 | "object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(t){return 10>t?"0"+t:t}function this_value(){return this.valueOf()}function quote(t){return rx_escapable.lastIndex=0,rx_escapable.test(t)?'"'+t.replace(rx_escapable,function(t){var e=meta[t];return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'}function str(t,e){var r,n,o,u,f,a=gap,i=e[t];switch(i&&"object"==typeof i&&"function"==typeof i.toJSON&&(i=i.toJSON(t)),"function"==typeof rep&&(i=rep.call(e,t,i)),typeof i){case"string":return quote(i);case"number":return isFinite(i)?String(i):"null";case"boolean":case"null":return String(i);case"object":if(!i)return"null";if(gap+=indent,f=[],"[object Array]"===Object.prototype.toString.apply(i)){for(u=i.length,r=0;u>r;r+=1)f[r]=str(r,i)||"null";return o=0===f.length?"[]":gap?"[\n"+gap+f.join(",\n"+gap)+"\n"+a+"]":"["+f.join(",")+"]",gap=a,o}if(rep&&"object"==typeof rep)for(u=rep.length,r=0;u>r;r+=1)"string"==typeof rep[r]&&(n=rep[r],o=str(n,i),o&&f.push(quote(n)+(gap?": ":":")+o));else for(n in i)Object.prototype.hasOwnProperty.call(i,n)&&(o=str(n,i),o&&f.push(quote(n)+(gap?": ":":")+o));return o=0===f.length?"{}":gap?"{\n"+gap+f.join(",\n"+gap)+"\n"+a+"}":"{"+f.join(",")+"}",gap=a,o}}var rx_one=/^[\],:{}\s]*$/,rx_two=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,rx_three=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,rx_four=/(?:^|:|,)(?:\s*\[)+/g,rx_escapable=/[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,rx_dangerous=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},Boolean.prototype.toJSON=this_value,Number.prototype.toJSON=this_value,String.prototype.toJSON=this_value);var gap,indent,meta,rep;"function"!=typeof JSON.stringify&&(meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(t,e,r){var n;if(gap="",indent="","number"==typeof r)for(n=0;r>n;n+=1)indent+=" ";else"string"==typeof r&&(indent=r);if(rep=e,e&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw new Error("JSON.stringify");return str("",{"":t})}),"function"!=typeof JSON.parse&&(JSON.parse=function(text,reviver){function walk(t,e){var r,n,o=t[e];if(o&&"object"==typeof o)for(r in o)Object.prototype.hasOwnProperty.call(o,r)&&(n=walk(o,r),void 0!==n?o[r]=n:delete o[r]);return reviver.call(t,e,o)}var j;if(text=String(text),rx_dangerous.lastIndex=0,rx_dangerous.test(text)&&(text=text.replace(rx_dangerous,function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})),rx_one.test(text.replace(rx_two,"@").replace(rx_three,"]").replace(rx_four,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j;throw new SyntaxError("JSON.parse")})}(); -------------------------------------------------------------------------------- /sandcage.coffee: -------------------------------------------------------------------------------- 1 | 2 | class SandCage 3 | SANDCAGE_API={} 4 | API_VERSION = "0.2" 5 | ENDPOINT_BASE = "https://api.sandcage.com/#{API_VERSION}/" 6 | 7 | constructor: (@apikey) -> 8 | if not @apikey 9 | return {status: 'error', name: 'MissingKey', message: 'Provide your SandCage API Key.'} 10 | SANDCAGE_API = @ 11 | 12 | if not JSON? then @loadScript('json2.min.js') 13 | return @ 14 | 15 | @call: (service_endpoint, params, callback_endpoint, onresult) -> 16 | if not params? or params is {} then return false 17 | payload = key: SANDCAGE_API.apikey 18 | for key of params 19 | payload[key] = params[key] 20 | @ajaxCall(service_endpoint, payload, callback_endpoint, onresult) 21 | 22 | @ajaxCall: (service_endpoint, payload, callback_endpoint, onresult) -> 23 | ### 24 | global: XMLHttpRequest 25 | ### 26 | if not callback_endpoint then payload.callback_url = callback_endpoint 27 | payload = JSON.stringify(payload) 28 | req = new XMLHttpRequest() 29 | req.open('POST', "#{ENDPOINT_BASE}#{service_endpoint}", false) 30 | req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded') 31 | req.onreadystatechange = () -> 32 | if req.readyState isnt 4 then return false 33 | res = JSON.parse(req.responseText) 34 | res ?= {status: 'error', name: 'GenericError', message: 'An error occurred.'} 35 | if onresult 36 | onresult(res) 37 | else 38 | return false 39 | 40 | req.send(payload) 41 | 42 | @loadScript = (url) -> 43 | ### 44 | global: XMLHttpRequest 45 | ### 46 | req = new XMLHttpRequest() 47 | req.open 'GET', url, false 48 | req.onreadystatechange = -> 49 | if req.readyState is 4 50 | if req.status is 200 51 | scriptNode = document.createElement('script') 52 | scriptNode.setAttribute 'type', 'text/javascript' 53 | scriptNode.setAttribute 'charset', 'UTF-8' 54 | scriptNode.setAttribute 'src', url 55 | document.head.appendChild scriptNode 56 | return 57 | 58 | req.send null 59 | return 60 | 61 | ### 62 | The "get-info" service 63 | @param {Object} params the hash of the parameters to pass to the request 64 | @param {Function} onresult an optional callback to execute when the API call is made 65 | ### 66 | @getInfo: (params, onresult) -> 67 | if not onresult? then return false 68 | @call('get-info', params, '', onresult) 69 | 70 | ### 71 | The "list-files" service 72 | @param {Object} params the hash of the parameters to pass to the request 73 | @param {Function} onresult an optional callback to execute when the API call is made 74 | ### 75 | @listFiles: (params, onresult) -> 76 | if not onresult? then return false 77 | @call('list-files', params, '', onresult) 78 | 79 | ### 80 | The "schedule-tasks" service 81 | @param {Object} params the hash of the parameters to pass to the request 82 | @param {String} callback_endpoint an optional callback endpoint, to which a request will be sent whenever there is an update for any of the tasks included in this request. See https://www.sandcage.com/docs/0.2/schedule_tasks#callbacks for an example 83 | @param {Function} onresult an optional callback to execute when the API call is made 84 | ### 85 | @scheduleFiles: (params, callback_endpoint, onresult) -> 86 | @call('schedule-tasks', params, callback_endpoint, onresult) 87 | 88 | ### 89 | The "destroy-files" service 90 | @param {Object} params the hash of the parameters to pass to the request 91 | @param {String} callback_endpoint an optional callback endpoint, to which a request will be sent whenever there is an update for any of the tasks included in this request. See https://www.sandcage.com/docs/0.2/destroy_files#callbacks for an example 92 | @param {Function} onresult an optional callback to execute when the API call is made 93 | ### 94 | @destroyFiles: (params, callback_endpoint, onresult) -> 95 | @call('destroy-files', params, callback_endpoint, onresult) 96 | 97 | -------------------------------------------------------------------------------- /sandcage.js: -------------------------------------------------------------------------------- 1 | var SandCage; 2 | 3 | SandCage = (function() { 4 | var SANDCAGE_API = {}; 5 | var API_VERSION = "0.2"; 6 | var ENDPOINT_BASE = "https://api.sandcage.com/" + API_VERSION + "/"; 7 | 8 | function SandCage(apikey) { 9 | this.apikey = apikey; 10 | if (!this.apikey) { 11 | return {status: 'error', name: 'MissingKey', message: 'Provide your SandCage API Key.'}; 12 | } 13 | SANDCAGE_API = this; 14 | if (typeof JSON === "undefined" || JSON === null) { 15 | this.loadScript('json2.min.js'); 16 | } 17 | return this; 18 | } 19 | 20 | SandCage.call = function(service_endpoint, params, callback_endpoint, onresult) { 21 | var key, payload; 22 | if ((params == null) || params === {}) { 23 | return false; 24 | } 25 | payload = { 26 | key: SANDCAGE_API.apikey 27 | }; 28 | for (key in params) { 29 | payload[key] = params[key]; 30 | } 31 | return this.ajaxCall(service_endpoint, payload, callback_endpoint, onresult); 32 | }; 33 | 34 | SandCage.ajaxCall = function(service_endpoint, payload, callback_endpoint, onresult) { 35 | /* 36 | global: XMLHttpRequest 37 | */ 38 | var req; 39 | if (!callback_endpoint) { 40 | payload.callback_url = callback_endpoint; 41 | } 42 | payload = JSON.stringify(payload); 43 | req = new XMLHttpRequest(); 44 | req.open('POST', "" + ENDPOINT_BASE + service_endpoint, false); 45 | req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); 46 | req.onreadystatechange = function() { 47 | var res; 48 | if (req.readyState !== 4) { 49 | return false; 50 | } 51 | res = JSON.parse(req.responseText); 52 | if (res == null) { 53 | res = {status: 'error', name: 'GenericError', message: 'An error occurred.'}; 54 | } 55 | if (onresult) { 56 | return onresult(res); 57 | } else { 58 | return false; 59 | } 60 | }; 61 | return req.send(payload); 62 | }; 63 | 64 | SandCage.loadScript = function(url) { 65 | /* 66 | global: XMLHttpRequest 67 | */ 68 | var req; 69 | req = new XMLHttpRequest(); 70 | req.open('GET', url, false); 71 | req.onreadystatechange = function() { 72 | var scriptNode; 73 | if (req.readyState === 4) { 74 | if (req.status === 200) { 75 | scriptNode = document.createElement('script'); 76 | scriptNode.setAttribute('type', 'text/javascript'); 77 | scriptNode.setAttribute('charset', 'UTF-8'); 78 | scriptNode.setAttribute('src', url); 79 | document.head.appendChild(scriptNode); 80 | } 81 | } 82 | }; 83 | req.send(null); 84 | }; 85 | 86 | /* 87 | The "get-info" service 88 | @param {Object} params the hash of the parameters to pass to the request 89 | @param {Function} onresult an optional callback to execute when the API call is made 90 | */ 91 | SandCage.getInfo = function(params, onresult) { 92 | if (onresult == null) { 93 | return false; 94 | } 95 | return this.call('get-info', params, '', onresult); 96 | }; 97 | 98 | /* 99 | The "list-files" service 100 | @param {Object} params the hash of the parameters to pass to the request 101 | @param {Function} onresult an optional callback to execute when the API call is made 102 | */ 103 | SandCage.listFiles = function(params, onresult) { 104 | if (onresult == null) { 105 | return false; 106 | } 107 | return this.call('list-files', params, '', onresult); 108 | }; 109 | 110 | /* 111 | The "schedule-tasks" service 112 | @param {Object} params the hash of the parameters to pass to the request 113 | @param {String} callback_endpoint an optional callback endpoint, to which a request will be sent whenever there is an update for any of the tasks included in this request. See https://www.sandcage.com/docs/0.2/schedule_tasks#callbacks for an example 114 | @param {Function} onresult an optional callback to execute when the API call is made 115 | */ 116 | SandCage.scheduleFiles = function(params, callback_endpoint, onresult) { 117 | return this.call('schedule-tasks', params, callback_endpoint, onresult); 118 | }; 119 | 120 | /* 121 | The "destroy-files" service 122 | @param {Object} params the hash of the parameters to pass to the request 123 | @param {String} callback_endpoint an optional callback endpoint, to which a request will be sent whenever there is an update for any of the tasks included in this request. See https://www.sandcage.com/docs/0.2/destroy_files#callbacks for an example 124 | @param {Function} onresult an optional callback to execute when the API call is made 125 | */ 126 | SandCage.destroyFiles = function(params, callback_endpoint, onresult) { 127 | return this.call('destroy-files', params, callback_endpoint, onresult); 128 | }; 129 | 130 | return SandCage; 131 | })(); 132 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /json2.js: -------------------------------------------------------------------------------- 1 | // json2.js 2 | // 2016-05-01 3 | // Public Domain. 4 | // NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. 5 | // See http://www.JSON.org/js.html 6 | // This code should be minified before deployment. 7 | // See http://javascript.crockford.com/jsmin.html 8 | 9 | // USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO 10 | // NOT CONTROL. 11 | 12 | // This file creates a global JSON object containing two methods: stringify 13 | // and parse. This file is provides the ES5 JSON capability to ES3 systems. 14 | // If a project might run on IE8 or earlier, then this file should be included. 15 | // This file does nothing on ES5 systems. 16 | 17 | // JSON.stringify(value, replacer, space) 18 | // value any JavaScript value, usually an object or array. 19 | // replacer an optional parameter that determines how object 20 | // values are stringified for objects. It can be a 21 | // function or an array of strings. 22 | // space an optional parameter that specifies the indentation 23 | // of nested structures. If it is omitted, the text will 24 | // be packed without extra whitespace. If it is a number, 25 | // it will specify the number of spaces to indent at each 26 | // level. If it is a string (such as "\t" or " "), 27 | // it contains the characters used to indent at each level. 28 | // This method produces a JSON text from a JavaScript value. 29 | // When an object value is found, if the object contains a toJSON 30 | // method, its toJSON method will be called and the result will be 31 | // stringified. A toJSON method does not serialize: it returns the 32 | // value represented by the name/value pair that should be serialized, 33 | // or undefined if nothing should be serialized. The toJSON method 34 | // will be passed the key associated with the value, and this will be 35 | // bound to the value. 36 | 37 | // For example, this would serialize Dates as ISO strings. 38 | 39 | // Date.prototype.toJSON = function (key) { 40 | // function f(n) { 41 | // // Format integers to have at least two digits. 42 | // return (n < 10) 43 | // ? "0" + n 44 | // : n; 45 | // } 46 | // return this.getUTCFullYear() + "-" + 47 | // f(this.getUTCMonth() + 1) + "-" + 48 | // f(this.getUTCDate()) + "T" + 49 | // f(this.getUTCHours()) + ":" + 50 | // f(this.getUTCMinutes()) + ":" + 51 | // f(this.getUTCSeconds()) + "Z"; 52 | // }; 53 | 54 | // You can provide an optional replacer method. It will be passed the 55 | // key and value of each member, with this bound to the containing 56 | // object. The value that is returned from your method will be 57 | // serialized. If your method returns undefined, then the member will 58 | // be excluded from the serialization. 59 | 60 | // If the replacer parameter is an array of strings, then it will be 61 | // used to select the members to be serialized. It filters the results 62 | // such that only members with keys listed in the replacer array are 63 | // stringified. 64 | 65 | // Values that do not have JSON representations, such as undefined or 66 | // functions, will not be serialized. Such values in objects will be 67 | // dropped; in arrays they will be replaced with null. You can use 68 | // a replacer function to replace those with JSON values. 69 | 70 | // JSON.stringify(undefined) returns undefined. 71 | 72 | // The optional space parameter produces a stringification of the 73 | // value that is filled with line breaks and indentation to make it 74 | // easier to read. 75 | 76 | // If the space parameter is a non-empty string, then that string will 77 | // be used for indentation. If the space parameter is a number, then 78 | // the indentation will be that many spaces. 79 | 80 | // Example: 81 | 82 | // text = JSON.stringify(["e", {pluribus: "unum"}]); 83 | // // text is '["e",{"pluribus":"unum"}]' 84 | 85 | // text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t"); 86 | // // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' 87 | 88 | // text = JSON.stringify([new Date()], function (key, value) { 89 | // return this[key] instanceof Date 90 | // ? "Date(" + this[key] + ")" 91 | // : value; 92 | // }); 93 | // // text is '["Date(---current time---)"]' 94 | 95 | // JSON.parse(text, reviver) 96 | // This method parses a JSON text to produce an object or array. 97 | // It can throw a SyntaxError exception. 98 | 99 | // The optional reviver parameter is a function that can filter and 100 | // transform the results. It receives each of the keys and values, 101 | // and its return value is used instead of the original value. 102 | // If it returns what it received, then the structure is not modified. 103 | // If it returns undefined then the member is deleted. 104 | 105 | // Example: 106 | 107 | // // Parse the text. Values that look like ISO date strings will 108 | // // be converted to Date objects. 109 | 110 | // myData = JSON.parse(text, function (key, value) { 111 | // var a; 112 | // if (typeof value === "string") { 113 | // a = 114 | // /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); 115 | // if (a) { 116 | // return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], 117 | // +a[5], +a[6])); 118 | // } 119 | // } 120 | // return value; 121 | // }); 122 | 123 | // myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { 124 | // var d; 125 | // if (typeof value === "string" && 126 | // value.slice(0, 5) === "Date(" && 127 | // value.slice(-1) === ")") { 128 | // d = new Date(value.slice(5, -1)); 129 | // if (d) { 130 | // return d; 131 | // } 132 | // } 133 | // return value; 134 | // }); 135 | 136 | // This is a reference implementation. You are free to copy, modify, or 137 | // redistribute. 138 | 139 | /*jslint 140 | eval, for, this 141 | */ 142 | 143 | /*property 144 | JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, 145 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, 146 | lastIndex, length, parse, prototype, push, replace, slice, stringify, 147 | test, toJSON, toString, valueOf 148 | */ 149 | 150 | 151 | // Create a JSON object only if one does not already exist. We create the 152 | // methods in a closure to avoid creating global variables. 153 | 154 | if (typeof JSON !== "object") { 155 | JSON = {}; 156 | } 157 | 158 | (function () { 159 | "use strict"; 160 | 161 | var rx_one = /^[\],:{}\s]*$/; 162 | var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g; 163 | var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g; 164 | var rx_four = /(?:^|:|,)(?:\s*\[)+/g; 165 | var rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; 166 | var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; 167 | 168 | function f(n) { 169 | // Format integers to have at least two digits. 170 | return n < 10 171 | ? "0" + n 172 | : n; 173 | } 174 | 175 | function this_value() { 176 | return this.valueOf(); 177 | } 178 | 179 | if (typeof Date.prototype.toJSON !== "function") { 180 | 181 | Date.prototype.toJSON = function () { 182 | 183 | return isFinite(this.valueOf()) 184 | ? this.getUTCFullYear() + "-" + 185 | f(this.getUTCMonth() + 1) + "-" + 186 | f(this.getUTCDate()) + "T" + 187 | f(this.getUTCHours()) + ":" + 188 | f(this.getUTCMinutes()) + ":" + 189 | f(this.getUTCSeconds()) + "Z" 190 | : null; 191 | }; 192 | 193 | Boolean.prototype.toJSON = this_value; 194 | Number.prototype.toJSON = this_value; 195 | String.prototype.toJSON = this_value; 196 | } 197 | 198 | var gap; 199 | var indent; 200 | var meta; 201 | var rep; 202 | 203 | 204 | function quote(string) { 205 | 206 | // If the string contains no control characters, no quote characters, and no 207 | // backslash characters, then we can safely slap some quotes around it. 208 | // Otherwise we must also replace the offending characters with safe escape 209 | // sequences. 210 | 211 | rx_escapable.lastIndex = 0; 212 | return rx_escapable.test(string) 213 | ? "\"" + string.replace(rx_escapable, function (a) { 214 | var c = meta[a]; 215 | return typeof c === "string" 216 | ? c 217 | : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4); 218 | }) + "\"" 219 | : "\"" + string + "\""; 220 | } 221 | 222 | 223 | function str(key, holder) { 224 | 225 | // Produce a string from holder[key]. 226 | 227 | var i; // The loop counter. 228 | var k; // The member key. 229 | var v; // The member value. 230 | var length; 231 | var mind = gap; 232 | var partial; 233 | var value = holder[key]; 234 | 235 | // If the value has a toJSON method, call it to obtain a replacement value. 236 | 237 | if (value && typeof value === "object" && 238 | typeof value.toJSON === "function") { 239 | value = value.toJSON(key); 240 | } 241 | 242 | // If we were called with a replacer function, then call the replacer to 243 | // obtain a replacement value. 244 | 245 | if (typeof rep === "function") { 246 | value = rep.call(holder, key, value); 247 | } 248 | 249 | // What happens next depends on the value's type. 250 | 251 | switch (typeof value) { 252 | case "string": 253 | return quote(value); 254 | 255 | case "number": 256 | 257 | // JSON numbers must be finite. Encode non-finite numbers as null. 258 | 259 | return isFinite(value) 260 | ? String(value) 261 | : "null"; 262 | 263 | case "boolean": 264 | case "null": 265 | 266 | // If the value is a boolean or null, convert it to a string. Note: 267 | // typeof null does not produce "null". The case is included here in 268 | // the remote chance that this gets fixed someday. 269 | 270 | return String(value); 271 | 272 | // If the type is "object", we might be dealing with an object or an array or 273 | // null. 274 | 275 | case "object": 276 | 277 | // Due to a specification blunder in ECMAScript, typeof null is "object", 278 | // so watch out for that case. 279 | 280 | if (!value) { 281 | return "null"; 282 | } 283 | 284 | // Make an array to hold the partial results of stringifying this object value. 285 | 286 | gap += indent; 287 | partial = []; 288 | 289 | // Is the value an array? 290 | 291 | if (Object.prototype.toString.apply(value) === "[object Array]") { 292 | 293 | // The value is an array. Stringify every element. Use null as a placeholder 294 | // for non-JSON values. 295 | 296 | length = value.length; 297 | for (i = 0; i < length; i += 1) { 298 | partial[i] = str(i, value) || "null"; 299 | } 300 | 301 | // Join all of the elements together, separated with commas, and wrap them in 302 | // brackets. 303 | 304 | v = partial.length === 0 305 | ? "[]" 306 | : gap 307 | ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" 308 | : "[" + partial.join(",") + "]"; 309 | gap = mind; 310 | return v; 311 | } 312 | 313 | // If the replacer is an array, use it to select the members to be stringified. 314 | 315 | if (rep && typeof rep === "object") { 316 | length = rep.length; 317 | for (i = 0; i < length; i += 1) { 318 | if (typeof rep[i] === "string") { 319 | k = rep[i]; 320 | v = str(k, value); 321 | if (v) { 322 | partial.push(quote(k) + ( 323 | gap 324 | ? ": " 325 | : ":" 326 | ) + v); 327 | } 328 | } 329 | } 330 | } else { 331 | 332 | // Otherwise, iterate through all of the keys in the object. 333 | 334 | for (k in value) { 335 | if (Object.prototype.hasOwnProperty.call(value, k)) { 336 | v = str(k, value); 337 | if (v) { 338 | partial.push(quote(k) + ( 339 | gap 340 | ? ": " 341 | : ":" 342 | ) + v); 343 | } 344 | } 345 | } 346 | } 347 | 348 | // Join all of the member texts together, separated with commas, 349 | // and wrap them in braces. 350 | 351 | v = partial.length === 0 352 | ? "{}" 353 | : gap 354 | ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" 355 | : "{" + partial.join(",") + "}"; 356 | gap = mind; 357 | return v; 358 | } 359 | } 360 | 361 | // If the JSON object does not yet have a stringify method, give it one. 362 | 363 | if (typeof JSON.stringify !== "function") { 364 | meta = { // table of character substitutions 365 | "\b": "\\b", 366 | "\t": "\\t", 367 | "\n": "\\n", 368 | "\f": "\\f", 369 | "\r": "\\r", 370 | "\"": "\\\"", 371 | "\\": "\\\\" 372 | }; 373 | JSON.stringify = function (value, replacer, space) { 374 | 375 | // The stringify method takes a value and an optional replacer, and an optional 376 | // space parameter, and returns a JSON text. The replacer can be a function 377 | // that can replace values, or an array of strings that will select the keys. 378 | // A default replacer method can be provided. Use of the space parameter can 379 | // produce text that is more easily readable. 380 | 381 | var i; 382 | gap = ""; 383 | indent = ""; 384 | 385 | // If the space parameter is a number, make an indent string containing that 386 | // many spaces. 387 | 388 | if (typeof space === "number") { 389 | for (i = 0; i < space; i += 1) { 390 | indent += " "; 391 | } 392 | 393 | // If the space parameter is a string, it will be used as the indent string. 394 | 395 | } else if (typeof space === "string") { 396 | indent = space; 397 | } 398 | 399 | // If there is a replacer, it must be a function or an array. 400 | // Otherwise, throw an error. 401 | 402 | rep = replacer; 403 | if (replacer && typeof replacer !== "function" && 404 | (typeof replacer !== "object" || 405 | typeof replacer.length !== "number")) { 406 | throw new Error("JSON.stringify"); 407 | } 408 | 409 | // Make a fake root object containing our value under the key of "". 410 | // Return the result of stringifying the value. 411 | 412 | return str("", {"": value}); 413 | }; 414 | } 415 | 416 | 417 | // If the JSON object does not yet have a parse method, give it one. 418 | 419 | if (typeof JSON.parse !== "function") { 420 | JSON.parse = function (text, reviver) { 421 | 422 | // The parse method takes a text and an optional reviver function, and returns 423 | // a JavaScript value if the text is a valid JSON text. 424 | 425 | var j; 426 | 427 | function walk(holder, key) { 428 | 429 | // The walk method is used to recursively walk the resulting structure so 430 | // that modifications can be made. 431 | 432 | var k; 433 | var v; 434 | var value = holder[key]; 435 | if (value && typeof value === "object") { 436 | for (k in value) { 437 | if (Object.prototype.hasOwnProperty.call(value, k)) { 438 | v = walk(value, k); 439 | if (v !== undefined) { 440 | value[k] = v; 441 | } else { 442 | delete value[k]; 443 | } 444 | } 445 | } 446 | } 447 | return reviver.call(holder, key, value); 448 | } 449 | 450 | 451 | // Parsing happens in four stages. In the first stage, we replace certain 452 | // Unicode characters with escape sequences. JavaScript handles many characters 453 | // incorrectly, either silently deleting them, or treating them as line endings. 454 | 455 | text = String(text); 456 | rx_dangerous.lastIndex = 0; 457 | if (rx_dangerous.test(text)) { 458 | text = text.replace(rx_dangerous, function (a) { 459 | return "\\u" + 460 | ("0000" + a.charCodeAt(0).toString(16)).slice(-4); 461 | }); 462 | } 463 | 464 | // In the second stage, we run the text against regular expressions that look 465 | // for non-JSON patterns. We are especially concerned with "()" and "new" 466 | // because they can cause invocation, and "=" because it can cause mutation. 467 | // But just to be safe, we want to reject all unexpected forms. 468 | 469 | // We split the second stage into 4 regexp operations in order to work around 470 | // crippling inefficiencies in IE's and Safari's regexp engines. First we 471 | // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we 472 | // replace all simple value tokens with "]" characters. Third, we delete all 473 | // open brackets that follow a colon or comma or that begin the text. Finally, 474 | // we look to see that the remaining characters are only whitespace or "]" or 475 | // "," or ":" or "{" or "}". If that is so, then the text is safe for eval. 476 | 477 | if ( 478 | rx_one.test( 479 | text 480 | .replace(rx_two, "@") 481 | .replace(rx_three, "]") 482 | .replace(rx_four, "") 483 | ) 484 | ) { 485 | 486 | // In the third stage we use the eval function to compile the text into a 487 | // JavaScript structure. The "{" operator is subject to a syntactic ambiguity 488 | // in JavaScript: it can begin a block or an object literal. We wrap the text 489 | // in parens to eliminate the ambiguity. 490 | 491 | j = eval("(" + text + ")"); 492 | 493 | // In the optional fourth stage, we recursively walk the new structure, passing 494 | // each name/value pair to a reviver function for possible transformation. 495 | 496 | return (typeof reviver === "function") 497 | ? walk({"": j}, "") 498 | : j; 499 | } 500 | 501 | // If the text is not JSON parseable, then a SyntaxError is thrown. 502 | 503 | throw new SyntaxError("JSON.parse"); 504 | }; 505 | } 506 | }()); 507 | --------------------------------------------------------------------------------