3 require_once "Socket.php";
4 require_once "LoomClient.php";
5 require_once "Cipher.php";
6 require_once "bcbitwise.php";
9 * iPhone interface to the Loom folder.
10 * Don't run this unencrypted.
11 * See http://www.whoopis.com/howtos/apache-rewrite.html
12 * for unstructions on setting up a .htaccess file to rewrite
13 * http://... to https://...
17 if (get_magic_quotes_gpc()) return stripslashes($x);
21 $passphrase = mq($_POST['passphrase']);
22 $session = mq($_POST['session']);
23 $qty = mq($_POST['zip']);
24 $type = mq($_POST['type']);
25 $location = mq($_POST['location']);
26 $folderkv = mq($_POST['folderkv']);
27 $valueskv = mq($_POST['valueskv']);
28 $take = mq($_POST['take']);
29 $give = mq($_POST['give']);
30 $page = mq($_POST['page']);
31 $greendot = mq($_POST['greendot']);
32 $showfolder = mq($_POST['showfolder']);
33 $newname = mq($_POST['newname']);
34 $oldname = mq($_POST['oldname']);
35 $newlocation = mq($_POST['newlocation']);
36 $savename = mq($_POST['savename']);
37 $delete = mq($_POST['delete']);
38 $add_location = mq($_POST['add_location']);
39 $commit = mq($_POST['commit']);
41 $client = new LoomClient();
43 // Redefine $encrypt_key if you want to use one.
44 // It should be a 32-character hex string, as generated
45 // by the grid-tutotial.php "Tools" page.
46 $client->disable_warnings();
48 include "ip-config.php";
49 $client->reenable_warnings();
54 if ($encrypt_key != '') {
56 if ($session_cipher != '') {
57 if ($folderkv != '') {
58 $folderkv = $session_cipher->decrypthex($folderkv);
60 if ($valueskv != '') {
61 $valueskv = $session_cipher->decrypthex($valueskv);
71 if ($page == 'refresh') {
76 if ($folderkv != '') $folder = $client->parsekv($folderkv, TRUE);
77 if ($valueskv != '') $values = $client->parsekv($valueskv, TRUE);
80 if (($session == '' && $passphrase == '') ||
!login()) {
81 $onload = 'passphrase';
85 $values = scanFolder($folder);
86 $valueskv = $client->array2kv($values);
90 $title = "Loom Folder";
92 if ($page == 'main') doMain();
93 elseif ($page == 'locations') doLocations();
94 elseif ($page == 'add_location') doAddLocation();
95 elseif ($page == 'logout') doLogout();
99 if ($page == 'login') drawLogin();
100 elseif ($page == 'main') drawMain();
101 elseif ($page == 'locations') drawLocations();
102 elseif ($page == 'add_location') drawAddLocation();
107 global $qty, $type, $location, $take, $give;
108 global $client, $folder, $folder_loc, $folder_name;
109 global $values, $valueskv;
114 if ($type != '-- choose asset --') {
115 $t = $folder['types'][$type];
118 $min_precision = $t['min_precision'];
119 if ($min_precision == '') $min_precision = 0;
120 $scale = $t['scale'];
121 if ($scale == '') $scale = 0;
124 if ($location != '-- choose location --') {
125 $loc = $folder['locs'][$location];
127 if ($id != '' && $loc != '') {
128 if ($scale != '') $count = bcmul($qty, bcpow(10, $scale), 0);
130 if ($count != '' && $id != '' && $loc != '') {
132 $client->buy($id, $folder_loc, $folder_loc, $url);
133 $res = $client->move($id, $count, $loc, $folder_loc, $url);
134 $loc_orig = $location;
135 $loc_dest = $folder_name;
136 } else if ($give != '') {
137 $client->buy($id, $loc, $folder_loc, $url);
138 $res = $client->move($id, $count, $folder_loc, $loc, $url);
139 $loc_dest = $location;
140 $loc_orig = $folder_name;
141 } else $transferred = FALSE;
143 $status = $res['status'];
144 if ($status == 'success') {
145 $value_orig = $client->applyScale($res['value_orig'], $min_precision, $scale);
146 $value_dest = $client->applyScale($res['value_dest'], $min_precision, $scale);
147 $values[$loc_orig][$type] = $value_orig;
148 ksort($values[$loc_orig]);
149 $values[$loc_dest][$type] = $value_dest;
150 ksort($values[$loc_dest]);
151 $valueskv = $client->array2kv($values);
152 } else $message = "Insufficient funds";
158 function doLocations() {
159 // Need to investigate how to delete.
160 // The "session" is an archive location containing the folder location
162 global $client, $folder, $values, $valueskv;
163 global $newname, $oldname;
164 global $savename, $delete, $add_location;
166 global $message, $title, $onload, $page;
169 $title = 'Loom Locations';
171 if ($savename != '') {
172 if ($newname == $oldname) return;
173 if ($folder['locs'][$newname] != '') {
174 $message = "Duplicate Location Name";
177 $res = $client->renameFolderLocation($session, $oldname, $newname);
182 else if ($add_location != '') {
183 $title = 'Loom Add Location';
184 $page = 'add_location';
187 else refreshFolder();
191 function makeCiphers() {
192 global $cipher, $encrypt_key, $session, $session_cipher;
193 if ($encrypt_key != '') {
195 $cipher = new Cipher($encrypt_key);
196 if ($session != '') $session = $cipher->decrypthex($session);
198 if ($session_cipher == '' && $session != '') {
199 $session_key = bcxorhex($session, $encrypt_key);
200 $session_cipher = new Cipher($session_key);
205 function doAddLocation() {
206 global $session, $commit, $page, $newname, $newlocation;
207 global $client, $message, $folder;
211 if ($commit != 'commit') $message = 'Cancelled';
212 else if ($newname == '') $message = 'Blank name';
213 else if ($folder['locs'][$newname] != '') $message = "Name already exists";
214 else if ($newlocation != '' && !$client->isValidID($newlocation)) {
215 $message = 'Invalid location ID';
217 if ($newlocation == '') $newlocation = $client->random
->random_id();
218 $client->newFolderLocation($session, $newname, $newlocation);
220 $message = "Location created: $newname";
224 function doLogout() {
225 global $page, $folderkv, $valueskv;
226 global $client, $session;
231 $client->logout($session);
234 function drawHead() {
235 global $title, $onload;
239 <meta name
="viewport" content
="width=device-width" user
-scalable
="no" minimum
-scale
="1.0" maximum
-scale
="1.0"/>
240 <title
><?
echo $title; ?
></title
>
241 <link rel
="apple-touch-icon" href
="krugerand.png"/>
242 <link rel
="shortcut icon" href
="krugerand.png"/>
244 <script language
="JavaScript">
245 function submitPage(page
) {
246 document
.forms
["mainform"].page
.value
= page
;
247 document
.mainform
.submit();
250 function greenDot(greendot
) {
251 document
.forms
["mainform"].greendot
.value
= greendot
;
252 document
.mainform
.submit();
255 function hideAddressbar() {
256 window
.scrollTo(0, 1);
259 function doOnLoad(selected
) {
261 setTimeout(hideAddressbar
, 250);
264 <?
additionalHTMLScripts(); ?
>
268 <style type
="text/css">
269 body
{ font
-family
: verdana
, arial
, sans
-serif
; font
-size
: 12pt
}
270 div
{ font
-size
:12pt
}
272 h1
{ font
-size
:14pt
}
273 h2
{ font
-size
:12pt
}
274 h3
{ font
-size
:10pt
}
275 td
{ font
-size
:12pt
}
276 ul
{ font
-size
:12pt
}
277 li
{ padding
-bottom
: 7px
}
278 pre
{ font
-family
: verdana
, arial
, sans
-serif
; }
279 A
:link
, A
:visited
{ color
:blue
; text
-decoration
:none
}
280 A
:hover
{ color
:blue
; text
-decoration
:underline
}
281 A
:active
{ color
:#FAD805; text-decoration:underline }
282 .tt
{ font
-family
: Courier
; font
-size
:10pt
}
283 .mono
{ font
-family
: monospace
; font
-size
: 11pt
}
284 .large_mono
{ font
-family
: monospace
; font
-size
: 10pt
}
285 .giant_mono
{ font
-family
: monospace
; font
-size
: 14pt
}
286 .tiny_mono
{ font
-family
: monospace
; font
-size
: 6pt
}
287 .normal
{ font
-size
:10pt
}
288 .smaller
{ font
-size
:6pt
}
289 .small
{ font
-size
:8pt
}
290 .large
{ font
-size
:12pt
}
291 .alarm
{ color
:red
; font
-weight
: bold
}
292 .focus_value
{ background
-color
:#DDDDDD }
293 .color_heading
{ margin
-top
:12px
; padding
:1px
; background
-color
:#DDDDDD; width:100% }
294 A
.label_link
{ font
-weight
:bold
; }
295 A
.highlight_link
{ font
-weight
:bold
; }
296 A
.cancel
{ background
-color
:#FFDDDD }
297 A
.plain
:link
, A
.plain
:visited
{ color
:black
; text
-decoration
:none
}
298 A
.plain
:hover
{ color
:blue
; text
-decoration
:underline
}
299 A
.plain
:active
{ color
:#FAD805; text-decoration:underline }
300 A
.name_dot
{ font
-size
:16pt
; font
-weight
:bold
; color
:green
; }
304 <body onload
="doOnLoad(document.forms[0].<? echo $onload; ?>)">
305 <table width
="320px">
310 function additionalHTMLScripts() {
313 if ($page == 'add_location') {
316 function Do0(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"0" ;}
317 function Do1(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"1" ;}
318 function Do2(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"2" ;}
319 function Do3(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"3" ;}
320 function Do4(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"4" ;}
321 function Do5(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"5" ;}
322 function Do6(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"6" ;}
323 function Do7(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"7" ;}
324 function Do8(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"8" ;}
325 function Do9(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"9" ;}
326 function DoA(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"a" ;}
327 function DoB(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"b" ;}
328 function DoC(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"c" ;}
329 function DoD(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"d" ;}
330 function DoE(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"e" ;}
331 function DoF(form
) { form
.newlocation
.value
= form
.newlocation
.value +
"f" ;}
332 function DoBksp(form
)
333 { var T
= form
.newlocation
.value
;
335 var T2
= T
.substr(0,L
-1);
336 form
.newlocation
.value
= T2
;
338 function DoClr(form
) { form
.newlocation
.value
= ""; }
339 function DoEnter(form
) { form
.submit(); }
340 function DoCancel(form
) {
341 form
.commit
.value
= 'Cancel';
344 function submitOnRet(e
, form
) {
347 if (window
.event
) keynum
= e
.keyCode
; // IE
348 else if (e
.which
) keynum
= e
.which
; // Netscape/Firefox/Opera
349 keychar
= String.fromCharCode(keynum
);
350 if (keychar
!= "\n" && keychar
!= "\r") return true;
359 function drawTail() {
367 function drawLogin() {
369 $host = $_SERVER["HTTP_HOST"];
370 if (!$host ||
$host == '') $host = $_SERVER["SERVER_NAME"];
374 <a href
="https://loom.cc/">Loom
</a
> for iPhone
. Note that in order to
use this
375 confidently
, you must trust that the PHP scripts at
<?
echo $host; ?
> do
376 not steal your passphrase
. I promise that unless somebody hacks my
377 site
, the code running is what you can download from
378 <a href
="./">here
</a
>, but don
't trust that unless you know
380 <form method="post" action="" autocomplete="off">
381 <input type="hidden" name="page" value="main"/>
385 <td><input type="password" name="passphrase" size="35" /></td>
389 <td><input type="submit" name="login" text="Login" /></td>
392 <p>Because my SSL certificate is a $20/year cheapie from
393 <a href="http://www.godaddy.com/">GoDaddy.com</a>, you'll see a warning message on your iPhone when you come here
: "The certificate for this website is invalid..." Click the
"Continue" button to go ahead
. Your regular browser should allow you to easily add the CA certificate to eliminate warnings
, but the iPhone browser does not
. In any
case, your connection to my web site will be encrypted
.</p
>
395 <p
>One way to
use this
, without giving me the keys to your kingdom
, is to create a separate
"Mobile" folder in Loom
. Transfer assets that you think you might need on the road to a drop
-point shared between your main folder
and the
"Mobile" folder
, and only aim this page at the
"Mobile" folder
. You can always login to your main folder directly via
396 <a href
="https://loom.cc/">
397 loom
.cc
</a
>, if you need something there
. The regular
interface isn
't as convenient as this one, but it works on the mobile browser.</p>
402 function hsc($text) {
403 return htmlspecialchars($text);
406 function hiddenValue($name) {
407 eval('global $
' . $name . ';');
408 echo '<input type
="hidden" name
="' . $name .
409 '" value
="' . hsc(eval('return $' . $name . ';')) . '"/>' . "\n";
412 function drawValues($name, $typevalues) {
413 if (is_array($typevalues)) {
415 foreach ($typevalues as $type => $value) {
418 $str .= "<b>$name</b>\n";
419 $str .= '<table border
="0"><tr
><td width
="50px"> 
;</td
><td
>';
420 $str .= '<table border
="0">' . "\n";
422 $str .= '<tr
><td align
="right">' . $value . "<td><td>$type</td></tr>\n";
427 echo "</table></td></tr></table>\n";
432 function writeSessionInfo() {
433 global $cipher, $session_cipher;
434 global $session, $folderkv, $valueskv;
436 $enc_session = $session;
437 $enc_folderkv = $folderkv;
438 $enc_valueskv = $valueskv;
440 if ($cipher) $enc_session = $cipher->encrypt2hex($enc_session);
441 if ($session_cipher) {
442 $enc_folderkv = $session_cipher->encrypt2hex($enc_folderkv);
443 $enc_valueskv = $session_cipher->encrypt2hex($enc_valueskv);
445 echo '<input type
="hidden" name
="session" value
="' . hsc($enc_session) . '"/>' . "\n";
446 echo '<input type
="hidden" name
="folderkv" value
="' . hsc($enc_folderkv) . '"/>' . "\n";
447 echo '<input type
="hidden" name
="valueskv" value
="' . hsc($enc_valueskv) . '"/>' . "\n";
450 function drawMain() {
451 global $session, $folder, $values, $folder_name;
452 global $qty, $type, $location;
458 <table border="0" width="99%" cellpadding="3">
460 <td colspan="2" style="background-color: #c0c0c0; text-align: center;"><span style="font-weight: normal; font-size: 110%;"><a href="javascript:submitPage('refresh
');">Refresh</a>
462 <a href="javascript:submitPage('locations
');">Locations</a>
464 <a href="javascript:submitPage('logout
');">Logout</a>
469 drawValues($folder_name, $values[$folder_name]);
471 <table border="0" width="99%">
472 <form name="mainform" method="post" action="" autocomplete="off">
478 <td align="right">Qty:</td>
479 <td><input style="font-size: 12pt;" type="text" size="25" name="zip" value="<? echo $qty; ?>" style="text-align:right;"></td>
483 <select name="type" style="font-size: 10pt;">
484 <option value="">-- choose asset --</option>
486 foreach ($folder['types
'] as $typename => $typearray) {
487 echo '<option value
="' . hsc($typename) . '"';
488 if ($type == $typename) echo ' selected
="selected"';
489 echo '>' . hsc($typename) . "</option>\n";
497 <select name="location" style="font-size: 10pt;">
498 <option value="">-- choose location --</option>
500 foreach($values as $loc => $value) {
501 if ($loc != $folder_name) {
502 echo '<option value
="' . hsc($loc) . '"';
503 if ($loc == $location) echo ' selected
="selected"';
504 echo '>' . hsc($loc) . "</option>\n";
513 <input style="font-size: 10pt;" type="submit" name="take" value="Take"/>
514 <input style="font-size: 10pt;" type="submit" name="give" value="Give"/>
518 if ($message != '') {
519 echo '<tr
><td
></td
><td
class="alarm">' . hsc($message) . "</td></tr>\n";
524 foreach ($values as $name => $typevalues) {
525 if ($name != $folder_name) {
526 drawValues($name, $typevalues);
533 function drawLocations() {
534 global $session, $folder, $values, $folder_name;
535 global $qty, $type, $location, $greendot;
540 <table border="0" width="99%" cellpadding="3">
542 <td colspan="2" style="background-color: #c0c0c0; text-align: center;"><span style="font-weight: normal; font-size: 110%;"><a href="javascript:submitPage('main
');">Folder</a>
544 <a href="javascript:submitPage('locations
');"><b>Locations</b></a>
546 <a href="javascript:submitPage('logout
');">Logout</a>
550 <table border="0" width="99%">
551 <form name="mainform" method="post" action="" autocomplete="off">
554 echo '<input type
="hidden" name
="zip" value
="' . $qty . '"/>' . "\n";
556 hiddenValue('location
');
557 hiddenValue('newname
');
558 hiddenValue('newlocation
');
561 <input type="hidden" name="greendot" value=""/>
564 <td valign="top"><a class=name_dot href="javascript: greenDot('<?
echo $folder_name; ?
>')" title="Edit Name"> • </a></td>
567 if ($greendot != $folder_name) echo "<b>$folder_name</b>";
569 echo '<input style
="font-size: 12pt;" type
="text" size
="25" name
="newname" value
="' . hsc($folder_name) . '"/><br
/>' . "\n";
570 echo '<input type
="hidden" name
="oldname" value
="' . hsc($folder_name) . '"/>' . "\n";
571 echo '<input type
="submit" name
="savename" value
="Save"/>' . "\n";
572 echo '<input type
="submit" name
="cancel" value
="Cancel"/>' . "\n";
575 $locs = $folder['locs
'];
576 foreach ($locs as $name => $loc) {
577 if ($name != $folder_name) {
580 <td valign="top"><a class=name_dot href="javascript: greenDot('<?
echo $name; ?
>')" title="Edit Name or Delete Folder"> • </a></td>
583 if ($greendot != $name) echo $name;
585 echo '<input style
="font-size: 12pt;" type
="text" size
="25" name
="newname" value
="' . hsc($name) . '"/><br
/>' . "\n";
586 echo '<input type
="hidden" name
="oldname" value
="' . hsc($name) . '"/>' . "\n";
587 echo '<input type
="submit" name
="savename" value
="Save"/>' . "\n";
588 echo '<input type
="submit" name
="cancel" value
="Cancel"/>' . "\n";
590 echo '<input type
="submit" disabled name
="delete" value
="Delete..."/><br
/>' . "\n";
591 echo '</td
></tr
><tr
><td colspan
="2"><span
class="mono">' . "<b>$loc</b></span><br/>\n";
596 if ($message != '') {
597 echo '<tr
><td colspan
="2" class="alarm">' . hsc($message) . "</td></tr>\n";
600 <tr><td colspan="2"><input type="submit" name="add_location" value="Add Location"/></td></tr>
603 <p>Click the green dot by a folder name to see its hex value, or to rename or delete it.</p>
607 function drawAddLocation() {
608 global $newname, $newlocation;
614 <form name="entryForm" method="post" action=""><b>
618 hiddenValue('commit
');
621 <input type="text" name="newname" style="font-size: 14pt;" size="25" value="<? echo $newname; ?>" onkeydown="submitOnRet(event, this.form)"/><br/>
622 Enter Location, blank for random:<br/>
623 <input type="text" style="font-size: 11pt;" size="32" name="newlocation" value="<? echo $newlocation; ?>" onkeydown="submitOnRet(event, this.form)"/>
626 <td><input type="button" style="font-size: 18pt;" value="7" onClick="Do7(this.form)"></td>
627 <td><input type="button" style="font-size: 18pt;" value="8" onClick="Do8(this.form)"></td>
628 <td><input type="button" style="font-size: 18pt;" value="9" onClick="Do9(this.form)"></td>
629 <td><input type="button" style="font-size: 18pt;" value="F" onClick="DoF(this.form)"></td>
632 <td><input type="button" style="font-size: 18pt;" value="4" onClick="Do4(this.form)"></td>
633 <td><input type="button" style="font-size: 18pt;" value="5" onClick="Do5(this.form)"></td>
634 <td><input type="button" style="font-size: 18pt;" value="6" onClick="Do6(this.form)"></td>
635 <td><input type="button" style="font-size: 18pt;" value="E" onClick="DoE(this.form)"></td>
638 <td><input type="button" style="font-size: 18pt;" value="1" onClick="Do1(this.form)"></td>
639 <td><input type="button" style="font-size: 18pt;" value="2" onClick="Do2(this.form)"></td>
640 <td><input type="button" style="font-size: 18pt;" value="3" onClick="Do3(this.form)"></td>
641 <td><input type="button" style="font-size: 18pt;" value="D" onClick="DoD(this.form)"></td>
644 <td><input type="button" style="font-size: 18pt;" value="0" onClick="Do0(this.form)"></td>
645 <td><input type="button" style="font-size: 18pt;" value="A" onClick="DoA(this.form)"></td>
646 <td><input type="button" style="font-size: 18pt;" value="B" onClick="DoB(this.form)"></td>
647 <td><input type="button" style="font-size: 18pt;" value="C" onClick="DoC(this.form)"></td>
651 <input type="button" style="font-size: 18pt;" value="Del" onClick="DoBksp(this.form)">
652 <input type="button" style="font-size: 18pt;" value="Clr" onClick="DoClr(this.form)">
653 <input type="button" style="font-size: 18pt;" value="Enter" onClick="DoEnter(this.form)"><br/>
654 <input type="button" style="font-size: 18pt;" value="Cancel" onClick="DoCancel(this.form)"><br/>
660 global $folder, $folder_name, $folder_loc;
662 if ($folder == '') return refreshFolder();
663 $folder_name = $folder['name
'];
664 $folder_loc = $folder['loc
'];
668 function refreshFolder() {
669 global $client, $passphrase, $session;
670 global $folder, $folderkv, $folder_name, $folder_loc;
674 if ($session != '') {
675 $res = $client->touch_archive($session, $url);
676 if ($res['status
'] == 'success
') $loc = $res['content
'];
680 if ($passphrase != '') {
681 $loc = $client->hash2location($client->sha256($passphrase));
682 $session = $client->folderSession($loc);
687 $res = $client->touch_archive($loc, $url);
688 if ($res['status
'] != 'success
') return FALSE;
689 $folder = $client->parseFolder($loc, $res['content
']);
690 $folderkv = $client->array2kv($folder);
692 $folder_name = $folder['name
'];
693 $folder_loc = $folder['loc
'];
697 function fullRefresh() {
698 global $client, $folder, $values, $valueskv;
701 $values = scanFolder($folder);
702 $valueskv = $client->array2kv($values);
705 function blankToZero($x) {
706 if ($x == '') return 0;
710 // This is currently n-squared for pretty big n, since it has to do
711 // a web call for each location/type pair.
712 // Patrick has promised a scan() function in the web API that would
713 // allow it to be done with a single call.
714 /* Now uses Patrick's
scan() API call
715 function scanFolder($folder) {
718 $types = $folder['types'];
719 $locs = $folder['locs'];
721 foreach ($locs as $locname => $loc) {
722 $loc_values = array();
723 foreach ($types as $typename => $type) {
725 $min_precision = $type['min_precision'];
726 $scale = $type['scale'];
727 $res = $client->touch($id, $loc, $url);
728 if ($res['status'] == 'success') {
729 $value = $client->applyScale($res['value'], $min_precision, $scale);
730 $loc_values[$typename] = $value;
733 $values[$locname] = $loc_values;
739 function scanFolder($folder) {
742 return $client->namedScan($folder['locs'], $folder['types'], FALSE, $url);
746 // Copyright 2008 Bill St. Clair
748 // Licensed under the Apache License, Version 2.0 (the "License");
749 // you may not use this file except in compliance with the License.
750 // You may obtain a copy of the License at
752 // http://www.apache.org/licenses/LICENSE-2.0
754 // Unless required by applicable law or agreed to in writing, software
755 // distributed under the License is distributed on an "AS IS" BASIS,
756 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
757 // See the License for the specific language governing permissions
758 // and limitations under the License.