├── .gitignore
├── LICENSE.txt
├── README.md
├── dist
└── bundle.js
├── example
└── 01-simple-requests.html
├── package.json
├── src
├── agent.js
├── index.js
├── requests
│ ├── assets-request.js
│ ├── current-request.js
│ ├── probe-request.js
│ ├── protocol-request.js
│ └── sample-request.js
└── responses
│ ├── assets-response.js
│ ├── create-protocol-response.js
│ ├── devices-response.js
│ ├── error-response.js
│ ├── headers
│ ├── assets-header.js
│ ├── devices-header.js
│ ├── error-header.js
│ ├── protocol-header.js
│ └── streams-header.js
│ ├── protocol-response.js
│ └── streams-response.js
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | node_modules/*
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012 Phil Coltrane
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MTConnect-JS
2 |
3 | ## Overview
4 |
5 | MTConnect-JS is a library for accessing data from an MTConnect agent via Javascript in the browser.
6 | If the library is not served from the same origin as the agent, the agent must allow CORS requests, or the browser will block requests.
7 |
8 | (The library is being rewritten in modern Javascript, and to remove the JQuery dependencies. Some functionality may have changed or be unavailable during this process.)
9 |
10 | ## Installation
11 |
12 | > git clone https://github.com/pmcoltrane/MTConnect-JS.git
13 |
14 | ## Build
15 |
16 | > npm run build
17 |
18 | NPM will run webpack, and create a `dist/bundle.js` that can be included in an HTML <script> tag.
19 |
20 | ## Usage
21 |
22 | For usage, see the examples under the `example` folder.
23 |
24 | ## Further Information
25 |
26 | Information about MTConnect, including standards documents, may be found at the [MTConnect Institute website](http://mtconnect.org).
27 |
--------------------------------------------------------------------------------
/dist/bundle.js:
--------------------------------------------------------------------------------
1 | var MTConnect =
2 | /******/ (function(modules) { // webpackBootstrap
3 | /******/ // The module cache
4 | /******/ var installedModules = {};
5 | /******/
6 | /******/ // The require function
7 | /******/ function __webpack_require__(moduleId) {
8 | /******/
9 | /******/ // Check if module is in cache
10 | /******/ if(installedModules[moduleId]) {
11 | /******/ return installedModules[moduleId].exports;
12 | /******/ }
13 | /******/ // Create a new module (and put it into the cache)
14 | /******/ var module = installedModules[moduleId] = {
15 | /******/ i: moduleId,
16 | /******/ l: false,
17 | /******/ exports: {}
18 | /******/ };
19 | /******/
20 | /******/ // Execute the module function
21 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
22 | /******/
23 | /******/ // Flag the module as loaded
24 | /******/ module.l = true;
25 | /******/
26 | /******/ // Return the exports of the module
27 | /******/ return module.exports;
28 | /******/ }
29 | /******/
30 | /******/
31 | /******/ // expose the modules object (__webpack_modules__)
32 | /******/ __webpack_require__.m = modules;
33 | /******/
34 | /******/ // expose the module cache
35 | /******/ __webpack_require__.c = installedModules;
36 | /******/
37 | /******/ // define getter function for harmony exports
38 | /******/ __webpack_require__.d = function(exports, name, getter) {
39 | /******/ if(!__webpack_require__.o(exports, name)) {
40 | /******/ Object.defineProperty(exports, name, {
41 | /******/ configurable: false,
42 | /******/ enumerable: true,
43 | /******/ get: getter
44 | /******/ });
45 | /******/ }
46 | /******/ };
47 | /******/
48 | /******/ // getDefaultExport function for compatibility with non-harmony modules
49 | /******/ __webpack_require__.n = function(module) {
50 | /******/ var getter = module && module.__esModule ?
51 | /******/ function getDefault() { return module['default']; } :
52 | /******/ function getModuleExports() { return module; };
53 | /******/ __webpack_require__.d(getter, 'a', getter);
54 | /******/ return getter;
55 | /******/ };
56 | /******/
57 | /******/ // Object.prototype.hasOwnProperty.call
58 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
59 | /******/
60 | /******/ // __webpack_public_path__
61 | /******/ __webpack_require__.p = "";
62 | /******/
63 | /******/ // Load entry module and return exports
64 | /******/ return __webpack_require__(__webpack_require__.s = 3);
65 | /******/ })
66 | /************************************************************************/
67 | /******/ ([
68 | /* 0 */
69 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
70 |
71 | "use strict";
72 | class ProtocolRequest {
73 |
74 | constructor(baseUrl) {
75 | this.baseUrl = baseUrl;
76 | }
77 |
78 | buildUrl(components, query) {
79 | let url = this.baseUrl;
80 | if (!url.endsWith('/')) url += '/';
81 |
82 | // Join array of URL components into the path
83 | let pathString = components.filter(i => i).map(encodeURIComponent).join('/');
84 |
85 | // Create the querystring
86 | let queryComponents = [];
87 | if (query) for (let i in query) {
88 | if (!i || !query[i]) continue;
89 |
90 | let key = encodeURIComponent(i);
91 | let value = encodeURIComponent(query[i]);
92 | queryComponents.push(key + '=' + value);
93 | }
94 | let queryString = queryComponents.join("&");
95 | if (queryString) queryString = '?' + queryString;
96 |
97 | return url + pathString + queryString;
98 | }
99 |
100 | async send(url) {
101 | console.log('Send', url);
102 |
103 | return new Promise((resolve, reject) => {
104 | let xhr = new XMLHttpRequest();
105 | xhr.open('GET', url);
106 | xhr.onload = e => {
107 | if (xhr.readyState === 4) {
108 | if (xhr.status === 200) {
109 | //console.log(xhr.responseText)
110 | resolve(xhr.responseXML);
111 | } else {
112 | //console.error(xhr.statusText)
113 | reject(xhr.statusText);
114 | }
115 | }
116 | };
117 |
118 | xhr.onerror = e => {
119 | //console.error(xhr.statusText)
120 | reject(xhr.statusText);
121 | };
122 |
123 | xhr.send(null);
124 | });
125 | }
126 |
127 | }
128 | /* harmony export (immutable) */ __webpack_exports__["a"] = ProtocolRequest;
129 |
130 |
131 | /***/ }),
132 | /* 1 */
133 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
134 |
135 | "use strict";
136 | class ProtocolHeader {
137 | constructor(xmlElem) {
138 | this.xmlElement = xmlElem;
139 |
140 | if (!xmlElem || !xmlElem.getAttribute) throw new Error('Header element not valid.');
141 |
142 | // Extract common attributes
143 | this.creationTime = Date.parse(xmlElem.getAttribute('creationTime'));
144 | this.sender = xmlElem.getAttribute('sender');
145 | this.instanceId = Number(xmlElem.getAttribute('instanceId'));
146 | this.version = xmlElem.getAttribute('version');
147 | }
148 | }
149 | /* harmony export (immutable) */ __webpack_exports__["a"] = ProtocolHeader;
150 |
151 |
152 | /***/ }),
153 | /* 2 */
154 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
155 |
156 | "use strict";
157 | class ProtocolResponse {
158 | constructor(xmlDoc) {
159 | this.xmlDocument = xmlDoc;
160 | this.documentType = xmlDoc.documentElement.tagName;
161 | this.isError = false;
162 | }
163 |
164 | }
165 | /* harmony export (immutable) */ __webpack_exports__["a"] = ProtocolResponse;
166 |
167 |
168 | /***/ }),
169 | /* 3 */
170 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
171 |
172 | "use strict";
173 | Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
174 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__requests_assets_request__ = __webpack_require__(4);
175 | /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "AssetsRequest", function() { return __WEBPACK_IMPORTED_MODULE_0__requests_assets_request__["a"]; });
176 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__requests_current_request__ = __webpack_require__(5);
177 | /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "CurrentRequest", function() { return __WEBPACK_IMPORTED_MODULE_1__requests_current_request__["a"]; });
178 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__requests_probe_request__ = __webpack_require__(6);
179 | /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ProbeRequest", function() { return __WEBPACK_IMPORTED_MODULE_2__requests_probe_request__["a"]; });
180 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__requests_sample_request__ = __webpack_require__(7);
181 | /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "SampleRequest", function() { return __WEBPACK_IMPORTED_MODULE_3__requests_sample_request__["a"]; });
182 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__responses_create_protocol_response__ = __webpack_require__(8);
183 | /* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "ProcessResponse", function() { return __WEBPACK_IMPORTED_MODULE_4__responses_create_protocol_response__["a"]; });
184 |
185 |
186 |
187 |
188 |
189 |
190 | console.log('MTConnect');
191 |
192 | /***/ }),
193 | /* 4 */
194 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
195 |
196 | "use strict";
197 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_request__ = __webpack_require__(0);
198 |
199 |
200 | class AssetsRequest extends __WEBPACK_IMPORTED_MODULE_0__protocol_request__["a" /* default */] {
201 |
202 | constructor(baseUrl, options) {
203 | super(baseUrl);
204 | this._options = options;
205 | }
206 |
207 | async execute() {
208 | let url = this.buildUrl(['asset'], this._options);
209 | return this.send(url);
210 | }
211 |
212 | }
213 | /* harmony export (immutable) */ __webpack_exports__["a"] = AssetsRequest;
214 |
215 |
216 | /***/ }),
217 | /* 5 */
218 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
219 |
220 | "use strict";
221 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__ = __webpack_require__(0);
222 |
223 |
224 | class CurrentRequest extends __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__["a" /* default */] {
225 |
226 | constructor(baseUrl, options) {
227 | super(baseUrl);
228 | this._options = options || {};
229 | }
230 |
231 | get at() {
232 | return this._options.at;
233 | }
234 | set at(value) {
235 | this._options.at = value;
236 | }
237 |
238 | get path() {
239 | return this._options.path;
240 | }
241 | set path(value) {
242 | this._options.path = value;
243 | }
244 |
245 | async execute() {
246 | let url = this.buildUrl(['current'], this._options);
247 | return this.send(url);
248 | }
249 |
250 | }
251 | /* harmony export (immutable) */ __webpack_exports__["a"] = CurrentRequest;
252 |
253 |
254 | /***/ }),
255 | /* 6 */
256 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
257 |
258 | "use strict";
259 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__ = __webpack_require__(0);
260 |
261 |
262 | class ProbeRequest extends __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__["a" /* default */] {
263 |
264 | constructor(baseUrl, deviceName) {
265 | super(baseUrl);
266 | this._deviceName = deviceName;
267 | }
268 |
269 | get deviceName() {
270 | return this._deviceName;
271 | }
272 | set deviceName(value) {
273 | this._deviceName = value;
274 | }
275 |
276 | async execute() {
277 | let url = this.buildUrl([this.deviceName]);
278 | return this.send(url);
279 | }
280 |
281 | }
282 | /* harmony export (immutable) */ __webpack_exports__["a"] = ProbeRequest;
283 |
284 |
285 | /***/ }),
286 | /* 7 */
287 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
288 |
289 | "use strict";
290 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__ = __webpack_require__(0);
291 |
292 |
293 | class SampleRequest extends __WEBPACK_IMPORTED_MODULE_0__protocol_request_js__["a" /* default */] {
294 |
295 | constructor(baseUrl, options) {
296 | super(baseUrl);
297 | this._options = options || {};
298 | }
299 |
300 | get from() {
301 | return this._options.from;
302 | }
303 | set from(value) {
304 | this._options.from = value;
305 | }
306 |
307 | get count() {
308 | return this._options.count;
309 | }
310 | set count(value) {
311 | this._options.count = value;
312 | }
313 |
314 | get path() {
315 | return this._options.path;
316 | }
317 | set path(value) {
318 | this._options.path = value;
319 | }
320 |
321 | async execute() {
322 | let url = this.buildUrl(['sample'], this._options);
323 | return this.send(url);
324 | }
325 |
326 | }
327 | /* harmony export (immutable) */ __webpack_exports__["a"] = SampleRequest;
328 |
329 |
330 | /***/ }),
331 | /* 8 */
332 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
333 |
334 | "use strict";
335 | /* harmony export (immutable) */ __webpack_exports__["a"] = CreateProtocolResponse;
336 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__assets_response__ = __webpack_require__(9);
337 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__devices_response__ = __webpack_require__(11);
338 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__error_response__ = __webpack_require__(13);
339 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__streams_response__ = __webpack_require__(15);
340 |
341 |
342 |
343 |
344 |
345 | function CreateProtocolResponse(xmlDoc) {
346 | if (!xmlDoc || !xmlDoc.documentElement || !xmlDoc.documentElement.tagName) {
347 | throw new Error('Document is not a valid document.');
348 | }
349 |
350 | let documentTag = xmlDoc.documentElement.tagName;
351 |
352 | if (documentTag === 'MTConnectDevices') {
353 | return new __WEBPACK_IMPORTED_MODULE_1__devices_response__["a" /* default */](xmlDoc);
354 | } else if (documentTag === 'MTConnectStreams') {
355 | return new __WEBPACK_IMPORTED_MODULE_3__streams_response__["a" /* default */](xmlDoc);
356 | } else if (documentTag === 'MTConnectAssets') {
357 | return new __WEBPACK_IMPORTED_MODULE_0__assets_response__["a" /* default */](xmlDoc);
358 | } else if (documentTag === 'MTConnectError') {
359 | return new __WEBPACK_IMPORTED_MODULE_2__error_response__["a" /* default */](xmlDoc);
360 | } else {
361 | throw new Error('Document is not a recognized MTConnect document.');
362 | }
363 | }
364 |
365 | /***/ }),
366 | /* 9 */
367 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
368 |
369 | "use strict";
370 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__headers_assets_header__ = __webpack_require__(10);
371 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__protocol_response__ = __webpack_require__(2);
372 |
373 |
374 |
375 | class AssetsResponse extends __WEBPACK_IMPORTED_MODULE_1__protocol_response__["a" /* default */] {
376 | constructor(xmlDoc) {
377 | super(xmlDoc);
378 |
379 | let headerElem = xmlDoc.getElementsByTagName('Header')[0];
380 | this.header = new __WEBPACK_IMPORTED_MODULE_0__headers_assets_header__["a" /* default */](headerElem);
381 | }
382 | }
383 | /* harmony export (immutable) */ __webpack_exports__["a"] = AssetsResponse;
384 |
385 |
386 | /***/ }),
387 | /* 10 */
388 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
389 |
390 | "use strict";
391 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_header__ = __webpack_require__(1);
392 |
393 |
394 | class AssetsHeader extends __WEBPACK_IMPORTED_MODULE_0__protocol_header__["a" /* default */] {
395 | constructor(xmlElem) {
396 | super(xmlElem);
397 |
398 | // Extract Assets attributes
399 | this.assetBufferSize = Number(xmlElem.getAttribute('assetBufferSize'));
400 | this.assetCount = Number(xmlElem.getAttribute('assetCount'));
401 | }
402 | }
403 | /* harmony export (immutable) */ __webpack_exports__["a"] = AssetsHeader;
404 |
405 |
406 | /***/ }),
407 | /* 11 */
408 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
409 |
410 | "use strict";
411 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__headers_devices_header__ = __webpack_require__(12);
412 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__protocol_response__ = __webpack_require__(2);
413 |
414 |
415 |
416 | class DevicesResponse extends __WEBPACK_IMPORTED_MODULE_1__protocol_response__["a" /* default */] {
417 | constructor(xmlDoc) {
418 | super(xmlDoc);
419 |
420 | let headerElem = xmlDoc.getElementsByTagName('Header')[0];
421 | this.header = new __WEBPACK_IMPORTED_MODULE_0__headers_devices_header__["a" /* default */](headerElem);
422 | }
423 | }
424 | /* harmony export (immutable) */ __webpack_exports__["a"] = DevicesResponse;
425 |
426 |
427 | /***/ }),
428 | /* 12 */
429 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
430 |
431 | "use strict";
432 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_header__ = __webpack_require__(1);
433 |
434 |
435 | class DevicesHeader extends __WEBPACK_IMPORTED_MODULE_0__protocol_header__["a" /* default */] {
436 | constructor(xmlElem) {
437 | super(xmlElem);
438 |
439 | // Extract Devices attributes
440 | this.assetBufferSize = Number(xmlElem.getAttribute('assetBufferSize'));
441 | this.assetCount = Number(xmlElem.getAttribute('assetCount'));
442 | this.bufferSize = Number(xmlElem.getAttribute('bufferSize'));
443 | }
444 | }
445 | /* harmony export (immutable) */ __webpack_exports__["a"] = DevicesHeader;
446 |
447 |
448 | /***/ }),
449 | /* 13 */
450 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
451 |
452 | "use strict";
453 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__headers_error_header__ = __webpack_require__(14);
454 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__protocol_response__ = __webpack_require__(2);
455 |
456 |
457 |
458 | class ErrorResponse extends __WEBPACK_IMPORTED_MODULE_1__protocol_response__["a" /* default */] {
459 | constructor(xmlDoc) {
460 | super(xmlDoc);
461 |
462 | let headerElem = xmlDoc.getElementsByTagName('Header')[0];
463 | this.header = new __WEBPACK_IMPORTED_MODULE_0__headers_error_header__["a" /* default */](headerElem);
464 | this.isError = true;
465 | }
466 | }
467 | /* harmony export (immutable) */ __webpack_exports__["a"] = ErrorResponse;
468 |
469 |
470 | /***/ }),
471 | /* 14 */
472 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
473 |
474 | "use strict";
475 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_header__ = __webpack_require__(1);
476 |
477 |
478 | class ErrorHeader extends __WEBPACK_IMPORTED_MODULE_0__protocol_header__["a" /* default */] {
479 | constructor(xmlElem) {
480 | super(xmlElem);
481 |
482 | // Extract Error attributes
483 | this.bufferSize = Number(xmlElem.getAttribute('bufferSize'));
484 | }
485 | }
486 | /* harmony export (immutable) */ __webpack_exports__["a"] = ErrorHeader;
487 |
488 |
489 | /***/ }),
490 | /* 15 */
491 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
492 |
493 | "use strict";
494 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__headers_streams_header__ = __webpack_require__(16);
495 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__protocol_response__ = __webpack_require__(2);
496 |
497 |
498 |
499 | class StreamsResponse extends __WEBPACK_IMPORTED_MODULE_1__protocol_response__["a" /* default */] {
500 | constructor(xmlDoc) {
501 | super(xmlDoc);
502 |
503 | let headerElem = xmlDoc.getElementsByTagName('Header')[0];
504 | this.header = new __WEBPACK_IMPORTED_MODULE_0__headers_streams_header__["a" /* default */](headerElem);
505 | }
506 | }
507 | /* harmony export (immutable) */ __webpack_exports__["a"] = StreamsResponse;
508 |
509 |
510 | /***/ }),
511 | /* 16 */
512 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
513 |
514 | "use strict";
515 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__protocol_header__ = __webpack_require__(1);
516 |
517 |
518 | class StreamsHeader extends __WEBPACK_IMPORTED_MODULE_0__protocol_header__["a" /* default */] {
519 | constructor(xmlElem) {
520 | super(xmlElem);
521 |
522 | // Extract Streams attributes
523 | this.bufferSize = Number(xmlElem.getAttribute('bufferSize'));
524 | this.nextSequence = Number(xmlElem.getAttribute('nextSequence'));
525 | this.firstSequence = Number(xmlElem.getAttribute('firstSequence'));
526 | this.lastSequence = Number(xmlElem.getAttribute('lastSequence'));
527 | }
528 | }
529 | /* harmony export (immutable) */ __webpack_exports__["a"] = StreamsHeader;
530 |
531 |
532 | /***/ })
533 | /******/ ]);
--------------------------------------------------------------------------------
/example/01-simple-requests.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |