sheep-market

10.000 sheep created by online workers  https://p.ce9e.org/sheep-market/
git clone https://git.ce9e.org/sheep-market.git

commit
207de367c468cee4f2831a4fbe1f8ede70fd6f0f
parent
a7fc7e3af82a0364b358646a990223aa5d50d81b
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2025-08-12 06:19
convert data to binary encoding

Diffstat

A cbor.js 406 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M index.html 1 +
A parse.py 39 +++++++++++++++++++++++++++++++++++++++
M sheep.js 44 ++++++++++++++------------------------------

4 files changed, 460 insertions, 30 deletions


diff --git a/cbor.js b/cbor.js

@@ -0,0 +1,406 @@
   -1     1 /*
   -1     2  * The MIT License (MIT)
   -1     3  *
   -1     4  * Copyright (c) 2014 Patrick Gansterer <paroga@paroga.com>
   -1     5  *
   -1     6  * Permission is hereby granted, free of charge, to any person obtaining a copy
   -1     7  * of this software and associated documentation files (the "Software"), to deal
   -1     8  * in the Software without restriction, including without limitation the rights
   -1     9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   -1    10  * copies of the Software, and to permit persons to whom the Software is
   -1    11  * furnished to do so, subject to the following conditions:
   -1    12  *
   -1    13  * The above copyright notice and this permission notice shall be included in all
   -1    14  * copies or substantial portions of the Software.
   -1    15  *
   -1    16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   -1    17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   -1    18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   -1    19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   -1    20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   -1    21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   -1    22  * SOFTWARE.
   -1    23  */
   -1    24 
   -1    25 (function(global, undefined) { "use strict";
   -1    26 var POW_2_24 = Math.pow(2, -24),
   -1    27     POW_2_32 = Math.pow(2, 32),
   -1    28     POW_2_53 = Math.pow(2, 53);
   -1    29 
   -1    30 function encode(value) {
   -1    31   var data = new ArrayBuffer(256);
   -1    32   var dataView = new DataView(data);
   -1    33   var lastLength;
   -1    34   var offset = 0;
   -1    35 
   -1    36   function ensureSpace(length) {
   -1    37     var newByteLength = data.byteLength;
   -1    38     var requiredLength = offset + length;
   -1    39     while (newByteLength < requiredLength)
   -1    40       newByteLength *= 2;
   -1    41     if (newByteLength !== data.byteLength) {
   -1    42       var oldDataView = dataView;
   -1    43       data = new ArrayBuffer(newByteLength);
   -1    44       dataView = new DataView(data);
   -1    45       var uint32count = (offset + 3) >> 2;
   -1    46       for (var i = 0; i < uint32count; ++i)
   -1    47         dataView.setUint32(i * 4, oldDataView.getUint32(i * 4));
   -1    48     }
   -1    49 
   -1    50     lastLength = length;
   -1    51     return dataView;
   -1    52   }
   -1    53   function write() {
   -1    54     offset += lastLength;
   -1    55   }
   -1    56   function writeFloat64(value) {
   -1    57     write(ensureSpace(8).setFloat64(offset, value));
   -1    58   }
   -1    59   function writeUint8(value) {
   -1    60     write(ensureSpace(1).setUint8(offset, value));
   -1    61   }
   -1    62   function writeUint8Array(value) {
   -1    63     var dataView = ensureSpace(value.length);
   -1    64     for (var i = 0; i < value.length; ++i)
   -1    65       dataView.setUint8(offset + i, value[i]);
   -1    66     write();
   -1    67   }
   -1    68   function writeUint16(value) {
   -1    69     write(ensureSpace(2).setUint16(offset, value));
   -1    70   }
   -1    71   function writeUint32(value) {
   -1    72     write(ensureSpace(4).setUint32(offset, value));
   -1    73   }
   -1    74   function writeUint64(value) {
   -1    75     var low = value % POW_2_32;
   -1    76     var high = (value - low) / POW_2_32;
   -1    77     var dataView = ensureSpace(8);
   -1    78     dataView.setUint32(offset, high);
   -1    79     dataView.setUint32(offset + 4, low);
   -1    80     write();
   -1    81   }
   -1    82   function writeTypeAndLength(type, length) {
   -1    83     if (length < 24) {
   -1    84       writeUint8(type << 5 | length);
   -1    85     } else if (length < 0x100) {
   -1    86       writeUint8(type << 5 | 24);
   -1    87       writeUint8(length);
   -1    88     } else if (length < 0x10000) {
   -1    89       writeUint8(type << 5 | 25);
   -1    90       writeUint16(length);
   -1    91     } else if (length < 0x100000000) {
   -1    92       writeUint8(type << 5 | 26);
   -1    93       writeUint32(length);
   -1    94     } else {
   -1    95       writeUint8(type << 5 | 27);
   -1    96       writeUint64(length);
   -1    97     }
   -1    98   }
   -1    99 
   -1   100   function encodeItem(value) {
   -1   101     var i;
   -1   102 
   -1   103     if (value === false)
   -1   104       return writeUint8(0xf4);
   -1   105     if (value === true)
   -1   106       return writeUint8(0xf5);
   -1   107     if (value === null)
   -1   108       return writeUint8(0xf6);
   -1   109     if (value === undefined)
   -1   110       return writeUint8(0xf7);
   -1   111 
   -1   112     switch (typeof value) {
   -1   113       case "number":
   -1   114         if (Math.floor(value) === value) {
   -1   115           if (0 <= value && value <= POW_2_53)
   -1   116             return writeTypeAndLength(0, value);
   -1   117           if (-POW_2_53 <= value && value < 0)
   -1   118             return writeTypeAndLength(1, -(value + 1));
   -1   119         }
   -1   120         writeUint8(0xfb);
   -1   121         return writeFloat64(value);
   -1   122 
   -1   123       case "string":
   -1   124         var utf8data = [];
   -1   125         for (i = 0; i < value.length; ++i) {
   -1   126           var charCode = value.charCodeAt(i);
   -1   127           if (charCode < 0x80) {
   -1   128             utf8data.push(charCode);
   -1   129           } else if (charCode < 0x800) {
   -1   130             utf8data.push(0xc0 | charCode >> 6);
   -1   131             utf8data.push(0x80 | charCode & 0x3f);
   -1   132           } else if (charCode < 0xd800) {
   -1   133             utf8data.push(0xe0 | charCode >> 12);
   -1   134             utf8data.push(0x80 | (charCode >> 6)  & 0x3f);
   -1   135             utf8data.push(0x80 | charCode & 0x3f);
   -1   136           } else {
   -1   137             charCode = (charCode & 0x3ff) << 10;
   -1   138             charCode |= value.charCodeAt(++i) & 0x3ff;
   -1   139             charCode += 0x10000;
   -1   140 
   -1   141             utf8data.push(0xf0 | charCode >> 18);
   -1   142             utf8data.push(0x80 | (charCode >> 12)  & 0x3f);
   -1   143             utf8data.push(0x80 | (charCode >> 6)  & 0x3f);
   -1   144             utf8data.push(0x80 | charCode & 0x3f);
   -1   145           }
   -1   146         }
   -1   147 
   -1   148         writeTypeAndLength(3, utf8data.length);
   -1   149         return writeUint8Array(utf8data);
   -1   150 
   -1   151       default:
   -1   152         var length;
   -1   153         if (Array.isArray(value)) {
   -1   154           length = value.length;
   -1   155           writeTypeAndLength(4, length);
   -1   156           for (i = 0; i < length; ++i)
   -1   157             encodeItem(value[i]);
   -1   158         } else if (value instanceof Uint8Array) {
   -1   159           writeTypeAndLength(2, value.length);
   -1   160           writeUint8Array(value);
   -1   161         } else {
   -1   162           var keys = Object.keys(value);
   -1   163           length = keys.length;
   -1   164           writeTypeAndLength(5, length);
   -1   165           for (i = 0; i < length; ++i) {
   -1   166             var key = keys[i];
   -1   167             encodeItem(key);
   -1   168             encodeItem(value[key]);
   -1   169           }
   -1   170         }
   -1   171     }
   -1   172   }
   -1   173 
   -1   174   encodeItem(value);
   -1   175 
   -1   176   if ("slice" in data)
   -1   177     return data.slice(0, offset);
   -1   178 
   -1   179   var ret = new ArrayBuffer(offset);
   -1   180   var retView = new DataView(ret);
   -1   181   for (var i = 0; i < offset; ++i)
   -1   182     retView.setUint8(i, dataView.getUint8(i));
   -1   183   return ret;
   -1   184 }
   -1   185 
   -1   186 function decode(data, tagger, simpleValue) {
   -1   187   var dataView = new DataView(data);
   -1   188   var offset = 0;
   -1   189 
   -1   190   if (typeof tagger !== "function")
   -1   191     tagger = function(value) { return value; };
   -1   192   if (typeof simpleValue !== "function")
   -1   193     simpleValue = function() { return undefined; };
   -1   194 
   -1   195   function read(value, length) {
   -1   196     offset += length;
   -1   197     return value;
   -1   198   }
   -1   199   function readArrayBuffer(length) {
   -1   200     return read(new Uint8Array(data, offset, length), length);
   -1   201   }
   -1   202   function readFloat16() {
   -1   203     var tempArrayBuffer = new ArrayBuffer(4);
   -1   204     var tempDataView = new DataView(tempArrayBuffer);
   -1   205     var value = readUint16();
   -1   206 
   -1   207     var sign = value & 0x8000;
   -1   208     var exponent = value & 0x7c00;
   -1   209     var fraction = value & 0x03ff;
   -1   210 
   -1   211     if (exponent === 0x7c00)
   -1   212       exponent = 0xff << 10;
   -1   213     else if (exponent !== 0)
   -1   214       exponent += (127 - 15) << 10;
   -1   215     else if (fraction !== 0)
   -1   216       return fraction * POW_2_24;
   -1   217 
   -1   218     tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13);
   -1   219     return tempDataView.getFloat32(0);
   -1   220   }
   -1   221   function readFloat32() {
   -1   222     return read(dataView.getFloat32(offset), 4);
   -1   223   }
   -1   224   function readFloat64() {
   -1   225     return read(dataView.getFloat64(offset), 8);
   -1   226   }
   -1   227   function readUint8() {
   -1   228     return read(dataView.getUint8(offset), 1);
   -1   229   }
   -1   230   function readUint16() {
   -1   231     return read(dataView.getUint16(offset), 2);
   -1   232   }
   -1   233   function readUint32() {
   -1   234     return read(dataView.getUint32(offset), 4);
   -1   235   }
   -1   236   function readUint64() {
   -1   237     return readUint32() * POW_2_32 + readUint32();
   -1   238   }
   -1   239   function readBreak() {
   -1   240     if (dataView.getUint8(offset) !== 0xff)
   -1   241       return false;
   -1   242     offset += 1;
   -1   243     return true;
   -1   244   }
   -1   245   function readLength(additionalInformation) {
   -1   246     if (additionalInformation < 24)
   -1   247       return additionalInformation;
   -1   248     if (additionalInformation === 24)
   -1   249       return readUint8();
   -1   250     if (additionalInformation === 25)
   -1   251       return readUint16();
   -1   252     if (additionalInformation === 26)
   -1   253       return readUint32();
   -1   254     if (additionalInformation === 27)
   -1   255       return readUint64();
   -1   256     if (additionalInformation === 31)
   -1   257       return -1;
   -1   258     throw "Invalid length encoding";
   -1   259   }
   -1   260   function readIndefiniteStringLength(majorType) {
   -1   261     var initialByte = readUint8();
   -1   262     if (initialByte === 0xff)
   -1   263       return -1;
   -1   264     var length = readLength(initialByte & 0x1f);
   -1   265     if (length < 0 || (initialByte >> 5) !== majorType)
   -1   266       throw "Invalid indefinite length element";
   -1   267     return length;
   -1   268   }
   -1   269 
   -1   270   function appendUtf16data(utf16data, length) {
   -1   271     for (var i = 0; i < length; ++i) {
   -1   272       var value = readUint8();
   -1   273       if (value & 0x80) {
   -1   274         if (value < 0xe0) {
   -1   275           value = (value & 0x1f) <<  6
   -1   276                 | (readUint8() & 0x3f);
   -1   277           length -= 1;
   -1   278         } else if (value < 0xf0) {
   -1   279           value = (value & 0x0f) << 12
   -1   280                 | (readUint8() & 0x3f) << 6
   -1   281                 | (readUint8() & 0x3f);
   -1   282           length -= 2;
   -1   283         } else {
   -1   284           value = (value & 0x0f) << 18
   -1   285                 | (readUint8() & 0x3f) << 12
   -1   286                 | (readUint8() & 0x3f) << 6
   -1   287                 | (readUint8() & 0x3f);
   -1   288           length -= 3;
   -1   289         }
   -1   290       }
   -1   291 
   -1   292       if (value < 0x10000) {
   -1   293         utf16data.push(value);
   -1   294       } else {
   -1   295         value -= 0x10000;
   -1   296         utf16data.push(0xd800 | (value >> 10));
   -1   297         utf16data.push(0xdc00 | (value & 0x3ff));
   -1   298       }
   -1   299     }
   -1   300   }
   -1   301 
   -1   302   function decodeItem() {
   -1   303     var initialByte = readUint8();
   -1   304     var majorType = initialByte >> 5;
   -1   305     var additionalInformation = initialByte & 0x1f;
   -1   306     var i;
   -1   307     var length;
   -1   308 
   -1   309     if (majorType === 7) {
   -1   310       switch (additionalInformation) {
   -1   311         case 25:
   -1   312           return readFloat16();
   -1   313         case 26:
   -1   314           return readFloat32();
   -1   315         case 27:
   -1   316           return readFloat64();
   -1   317       }
   -1   318     }
   -1   319 
   -1   320     length = readLength(additionalInformation);
   -1   321     if (length < 0 && (majorType < 2 || 6 < majorType))
   -1   322       throw "Invalid length";
   -1   323 
   -1   324     switch (majorType) {
   -1   325       case 0:
   -1   326         return length;
   -1   327       case 1:
   -1   328         return -1 - length;
   -1   329       case 2:
   -1   330         if (length < 0) {
   -1   331           var elements = [];
   -1   332           var fullArrayLength = 0;
   -1   333           while ((length = readIndefiniteStringLength(majorType)) >= 0) {
   -1   334             fullArrayLength += length;
   -1   335             elements.push(readArrayBuffer(length));
   -1   336           }
   -1   337           var fullArray = new Uint8Array(fullArrayLength);
   -1   338           var fullArrayOffset = 0;
   -1   339           for (i = 0; i < elements.length; ++i) {
   -1   340             fullArray.set(elements[i], fullArrayOffset);
   -1   341             fullArrayOffset += elements[i].length;
   -1   342           }
   -1   343           return fullArray;
   -1   344         }
   -1   345         return readArrayBuffer(length);
   -1   346       case 3:
   -1   347         var utf16data = [];
   -1   348         if (length < 0) {
   -1   349           while ((length = readIndefiniteStringLength(majorType)) >= 0)
   -1   350             appendUtf16data(utf16data, length);
   -1   351         } else
   -1   352           appendUtf16data(utf16data, length);
   -1   353         return String.fromCharCode.apply(null, utf16data);
   -1   354       case 4:
   -1   355         var retArray;
   -1   356         if (length < 0) {
   -1   357           retArray = [];
   -1   358           while (!readBreak())
   -1   359             retArray.push(decodeItem());
   -1   360         } else {
   -1   361           retArray = new Array(length);
   -1   362           for (i = 0; i < length; ++i)
   -1   363             retArray[i] = decodeItem();
   -1   364         }
   -1   365         return retArray;
   -1   366       case 5:
   -1   367         var retObject = {};
   -1   368         for (i = 0; i < length || length < 0 && !readBreak(); ++i) {
   -1   369           var key = decodeItem();
   -1   370           retObject[key] = decodeItem();
   -1   371         }
   -1   372         return retObject;
   -1   373       case 6:
   -1   374         return tagger(decodeItem(), length);
   -1   375       case 7:
   -1   376         switch (length) {
   -1   377           case 20:
   -1   378             return false;
   -1   379           case 21:
   -1   380             return true;
   -1   381           case 22:
   -1   382             return null;
   -1   383           case 23:
   -1   384             return undefined;
   -1   385           default:
   -1   386             return simpleValue(length);
   -1   387         }
   -1   388     }
   -1   389   }
   -1   390 
   -1   391   var ret = decodeItem();
   -1   392   if (offset !== data.byteLength)
   -1   393     throw "Remaining bytes";
   -1   394   return ret;
   -1   395 }
   -1   396 
   -1   397 var obj = { encode: encode, decode: decode };
   -1   398 
   -1   399 if (typeof define === "function" && define.amd)
   -1   400   define("cbor/cbor", obj);
   -1   401 else if (typeof module !== 'undefined' && module.exports)
   -1   402   module.exports = obj;
   -1   403 else if (!global.CBOR)
   -1   404   global.CBOR = obj;
   -1   405 
   -1   406 })(this);

diff --git a/index.html b/index.html

@@ -46,5 +46,6 @@
   46    46         </ul>
   47    47     </dialog>
   48    48 
   -1    49     <script src="cbor.js"></script>
   49    50     <script type="module" src="sheep.js"></script>
   50    51 </body>

diff --git a/parse.py b/parse.py

@@ -0,0 +1,39 @@
   -1     1 import sys
   -1     2 
   -1     3 import cbor
   -1     4 
   -1     5 
   -1     6 def parse_url(s):
   -1     7     data = []
   -1     8     parts = s.strip().lstrip('?').split('&')
   -1     9     for part in parts:
   -1    10         key, value = part.split('=', 1)
   -1    11         if key in ['xOff', 'yOff']:
   -1    12             data.append(round(float(value or '0') * 2))
   -1    13         else:
   -1    14             assert key == 'drawing'
   -1    15             for cmd in value.split('_'):
   -1    16                 cmd = cmd.split('.')
   -1    17                 if cmd[0] == 'lift':
   -1    18                     data.append([cmd[0]])
   -1    19                 elif cmd[0] in ['stroke', 'grey']:
   -1    20                     data.append([cmd[0], int(cmd[1], 10)])
   -1    21                 elif cmd[0].isdigit():
   -1    22                     data.append([int(x, 10) for x in cmd])
   -1    23     return data
   -1    24 
   -1    25 
   -1    26 def dump_url(data):
   -1    27     cmds = '_'.join('.'.join(str(x) for x in cmd) for cmd in data[2:])
   -1    28     return f'yOff={data[0] / 2}&xOff={data[1] / 2}&drawing={"_".join(cmds)}'
   -1    29 
   -1    30 
   -1    31 if __name__ == '__main__':
   -1    32     for k in range(0, 100):
   -1    33         items = []
   -1    34         for i in range(k * 100, (k + 1) * 100):
   -1    35             print(i + 1, end='\r', file=sys.stderr)
   -1    36             with open(f'data/{i + 1}') as fh:
   -1    37                 items.append(parse_url(fh.read()))
   -1    38         with open(f'bin/{k}', 'wb') as fh:
   -1    39             cbor.dump(items, fh)

diff --git a/sheep.js b/sheep.js

@@ -12,19 +12,6 @@ var hoverCol = 0;
   12    12 var hoverRow = 0;
   13    13 
   14    14 
   15    -1 var parseQuery = function(query) {
   16    -1 	query = query.trim();
   17    -1 	if (query[0] === '?') {
   18    -1 		query = query.substr(1);
   19    -1 	}
   20    -1 	var ret = {};
   21    -1 	query.split('&').forEach(part => {
   22    -1 		var a = part.split('=');
   23    -1 		ret[a[0]] = a[1];
   24    -1 	});
   25    -1 	return ret;
   26    -1 };
   27    -1 
   28    15 var grayToColor = function(gray) {
   29    16 	var c = ('00' + gray.toString(16)).substr(-2);
   30    17 	return '#' + c + c + c;
@@ -47,23 +34,20 @@ var eachWithTimeout = function(array, fn, timeout) {
   47    34 };
   48    35 
   49    36 var drawSheep = function(sheep) {
   50    -1 	var xOff = parseFloat(sheep.xOff, 10);
   51    -1 	var yOff = parseFloat(sheep.yOff, 10);
   -1    37 	var yOff = sheep[0] / 2;
   -1    38 	var xOff = sheep[1] / 2;
   52    39 
   53    40 	ctx.beginPath();
   54    -1 	return eachWithTimeout(sheep.drawing.split('_'), s => {
   55    -1 		var cmd = s.split('.');
   56    -1 
   -1    41 	return eachWithTimeout(sheep.slice(2), cmd => {
   57    42 		if (cmd[0] === 'lift') {
   58    43 			ctx.beginPath();
   59    44 		} else if (cmd[0] === 'stroke') {
   60    -1 			ctx.lineWidth = parseInt(cmd[1], 10);
   -1    45 			ctx.lineWidth = cmd[1];
   61    46 		} else if (cmd[0] === 'grey') {
   62    -1 			ctx.strokeStyle = grayToColor(parseInt(cmd[1], 10));
   63    -1 		} else if (parseInt(cmd[0], 10)) {
   64    -1 			var coords = cmd.map(x => parseInt(x, 10));
   65    -1 			ctx.moveTo(coords[2] + xOff, coords[3] + yOff);
   66    -1 			ctx.lineTo(coords[0] + xOff, coords[1] + yOff);
   -1    47 			ctx.strokeStyle = grayToColor(cmd[1]);
   -1    48 		} else {
   -1    49 			ctx.moveTo(cmd[2] + xOff, cmd[3] + yOff);
   -1    50 			ctx.lineTo(cmd[0] + xOff, cmd[1] + yOff);
   67    51 			ctx.stroke();
   68    52 		}
   69    53 	}, 10);
@@ -110,13 +94,13 @@ grid.addEventListener('keydown', event => {
  110    94 	}
  111    95 });
  112    96 
  113    -1 var q = parseQuery(location.search);
  114    -1 var id = parseInt(q.sheep, 10);
   -1    97 var q = new URLSearchParams(location.search);
   -1    98 var id = parseInt(q.get('sheep'), 10);
  115    99 if (id) {
  116    -1 	fetch('data/' + id)
  117    -1 		.then(r => r.text())
  118    -1 		.then(parseQuery)
  119    -1 		.then(drawSheep);
   -1   100 	var response = await fetch(`bin/${Math.floor((id - 1) / 100)}`);
   -1   101 	var data = CBOR.decode(await response.arrayBuffer());
   -1   102 	var sheep = data[(id - 1) % 100];
   -1   103 	drawSheep(sheep);
  120   104 
  121   105 	hoverRow = (id - 1) % rows;
  122   106 	hoverCol = Math.floor((id - 1) / rows);