manyfest 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.config/configstore/update-notifier-npm.json +1 -1
- package/README.md +365 -21
- package/examples/chocula/Chocula.js +8 -0
- package/examples/chocula/Data-Archive-org-Frankenberry.json +246 -0
- package/examples/chocula/Schema-Archive-org-Item.json +47 -0
- package/package.json +4 -3
- package/source/Manyfest-LogToConsole.js +1 -1
- package/source/Manyfest-ObjectAddressResolver.js +585 -0
- package/source/Manyfest.js +182 -112
- package/test/Data-Archive-org-Frankenberry.json +246 -0
- package/test/Data-Yahoo-Weather.json +115 -0
- package/test/Manyfest_Object_CheckExistence_tests.js +70 -0
- package/test/Manyfest_Object_Populate_tests.js +140 -0
- package/test/Manyfest_Object_Read_tests.js +166 -0
- package/test/Manyfest_Object_Validate_tests.js +82 -0
- package/test/Manyfest_Object_Write_tests.js +161 -0
- package/test/Manyfest_tests.js +34 -99
package/source/Manyfest.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* @author <steven@velozo.com>
|
|
4
4
|
*/
|
|
5
5
|
let libSimpleLog = require('./Manyfest-LogToConsole.js');
|
|
6
|
+
let libObjectAddressResolver = require('./Manyfest-ObjectAddressResolver.js');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Manyfest object address-based descriptions and manipulations.
|
|
@@ -11,15 +12,31 @@ let libSimpleLog = require('./Manyfest-LogToConsole.js');
|
|
|
11
12
|
*/
|
|
12
13
|
class Manyfest
|
|
13
14
|
{
|
|
14
|
-
constructor(pManifest, pInfoLog, pErrorLog)
|
|
15
|
+
constructor(pManifest, pInfoLog, pErrorLog, pOptions)
|
|
15
16
|
{
|
|
16
17
|
// Wire in logging
|
|
17
18
|
this.logInfo = (typeof(pInfoLog) === 'function') ? pInfoLog : libSimpleLog;
|
|
18
19
|
this.logError = (typeof(pErrorLog) === 'function') ? pErrorLog : libSimpleLog;
|
|
19
20
|
|
|
21
|
+
// Create an object address resolver and map in the functions
|
|
22
|
+
this.objectAddressResolver = new libObjectAddressResolver(this.logInfo, this.logError);
|
|
23
|
+
|
|
20
24
|
this.options = (
|
|
21
25
|
{
|
|
22
|
-
strict: false
|
|
26
|
+
strict: false,
|
|
27
|
+
defaultValues:
|
|
28
|
+
{
|
|
29
|
+
"String": "",
|
|
30
|
+
"Number": 0,
|
|
31
|
+
"Float": 0.0,
|
|
32
|
+
"Integer": 0,
|
|
33
|
+
"Boolean": false,
|
|
34
|
+
"Binary": 0,
|
|
35
|
+
"DateTime": 0,
|
|
36
|
+
"Array": [],
|
|
37
|
+
"Object": {},
|
|
38
|
+
"Null": null
|
|
39
|
+
}
|
|
23
40
|
});
|
|
24
41
|
|
|
25
42
|
this.scope = undefined;
|
|
@@ -72,12 +89,12 @@ class Manyfest
|
|
|
72
89
|
}
|
|
73
90
|
else
|
|
74
91
|
{
|
|
75
|
-
this.logError(`(${this.scope}) Error loading scope from manifest; expecting a string but property was type ${typeof(pManifest.Scope)}
|
|
92
|
+
this.logError(`(${this.scope}) Error loading scope from manifest; expecting a string but property was type ${typeof(pManifest.Scope)}.`, pManifest);
|
|
76
93
|
}
|
|
77
94
|
}
|
|
78
95
|
else
|
|
79
96
|
{
|
|
80
|
-
this.logError(`(${this.scope}) Error loading scope from manifest object. Property "Scope" does not exist in the root of the object
|
|
97
|
+
this.logError(`(${this.scope}) Error loading scope from manifest object. Property "Scope" does not exist in the root of the object.`, pManifest);
|
|
81
98
|
}
|
|
82
99
|
|
|
83
100
|
if (pManifest.hasOwnProperty('Descriptors'))
|
|
@@ -92,12 +109,12 @@ class Manyfest
|
|
|
92
109
|
}
|
|
93
110
|
else
|
|
94
111
|
{
|
|
95
|
-
this.logError(`(${this.scope}) Error loading description object from manifest object. Expecting an object in 'Manifest.Descriptors' but the property was type ${typeof(pManifest.
|
|
112
|
+
this.logError(`(${this.scope}) Error loading description object from manifest object. Expecting an object in 'Manifest.Descriptors' but the property was type ${typeof(pManifest.Descriptors)}.`, pManifest);
|
|
96
113
|
}
|
|
97
114
|
}
|
|
98
115
|
else
|
|
99
116
|
{
|
|
100
|
-
this.logError(`(${this.scope}) Error loading object description from manifest object. Property "Descriptors" does not exist in the root of the object
|
|
117
|
+
this.logError(`(${this.scope}) Error loading object description from manifest object. Property "Descriptors" does not exist in the root of the Manifest object.`, pManifest);
|
|
101
118
|
}
|
|
102
119
|
}
|
|
103
120
|
|
|
@@ -175,60 +192,47 @@ class Manyfest
|
|
|
175
192
|
/*************************************************************************
|
|
176
193
|
* Beginning of Object Manipulation (read & write) Functions
|
|
177
194
|
*/
|
|
178
|
-
//
|
|
179
|
-
|
|
195
|
+
// Check if an element exists by its hash
|
|
196
|
+
checkAddressExistsByHash (pObject, pHash)
|
|
180
197
|
{
|
|
181
198
|
if (this.elementHashes.hasOwnProperty(pHash))
|
|
182
199
|
{
|
|
183
|
-
return this.
|
|
200
|
+
return this.checkAddressExists(pObject, this.elementHashes[pHash]);
|
|
184
201
|
}
|
|
185
202
|
else
|
|
186
203
|
{
|
|
187
|
-
this.logError(`(${this.scope}) Error in
|
|
204
|
+
this.logError(`(${this.scope}) Error in checkAddressExistsByHash; the Hash ${pHash} doesn't exist in the schema.`);
|
|
188
205
|
return undefined;
|
|
189
206
|
}
|
|
190
207
|
}
|
|
191
208
|
|
|
192
|
-
//
|
|
193
|
-
|
|
209
|
+
// Check if an element exists at an address
|
|
210
|
+
checkAddressExists (pObject, pAddress)
|
|
194
211
|
{
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
// Make sure pAddress is a string
|
|
198
|
-
if (!typeof(pAddress) === 'string') return undefined;
|
|
212
|
+
return this.objectAddressResolver.checkAddressExists(pObject, pAddress);
|
|
213
|
+
}
|
|
199
214
|
|
|
200
|
-
let tmpSeparatorIndex = pAddress.indexOf('.');
|
|
201
215
|
|
|
202
|
-
|
|
216
|
+
// Get the value of an element by its hash
|
|
217
|
+
getValueByHash (pObject, pHash)
|
|
218
|
+
{
|
|
219
|
+
if (this.elementHashes.hasOwnProperty(pHash))
|
|
203
220
|
{
|
|
204
|
-
|
|
205
|
-
return pObject[pAddress];
|
|
221
|
+
return this.getValueAtAddress(pObject, this.elementHashes[pHash]);
|
|
206
222
|
}
|
|
207
223
|
else
|
|
208
224
|
{
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
// If there is an object property already named for the sub object, but it isn't an object
|
|
213
|
-
// then the system can't set the value in there. Error and abort!
|
|
214
|
-
if (pObject.hasOwnProperty(tmpSubObjectName) && typeof(pObject[tmpSubObjectName]) !== 'object')
|
|
215
|
-
{
|
|
216
|
-
return undefined;
|
|
217
|
-
}
|
|
218
|
-
else if (pObject.hasOwnProperty(tmpSubObjectName))
|
|
219
|
-
{
|
|
220
|
-
// If there is already a subobject pass that to the recursive thingy
|
|
221
|
-
return this.getValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress);
|
|
222
|
-
}
|
|
223
|
-
else
|
|
224
|
-
{
|
|
225
|
-
// Create a subobject and then pass that
|
|
226
|
-
pObject[tmpSubObjectName] = {};
|
|
227
|
-
return this.getValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress);
|
|
228
|
-
}
|
|
225
|
+
this.logError(`(${this.scope}) Error in getValueByHash; the Hash ${pHash} doesn't exist in the schema.`);
|
|
226
|
+
return undefined;
|
|
229
227
|
}
|
|
230
228
|
}
|
|
231
229
|
|
|
230
|
+
// Get the value of an element at an address
|
|
231
|
+
getValueAtAddress (pObject, pAddress)
|
|
232
|
+
{
|
|
233
|
+
return this.objectAddressResolver.getValueAtAddress(pObject, pAddress);
|
|
234
|
+
}
|
|
235
|
+
|
|
232
236
|
// Set the value of an element by its hash
|
|
233
237
|
setValueByHash(pObject, pHash, pValue)
|
|
234
238
|
{
|
|
@@ -243,79 +247,13 @@ class Manyfest
|
|
|
243
247
|
}
|
|
244
248
|
}
|
|
245
249
|
|
|
250
|
+
|
|
246
251
|
// Set the value of an element at an address
|
|
247
252
|
setValueAtAddress (pObject, pAddress, pValue)
|
|
248
253
|
{
|
|
249
|
-
|
|
250
|
-
if (!typeof(pObject) === 'object') return false;
|
|
251
|
-
// Make sure pAddress is a string
|
|
252
|
-
if (!typeof(pAddress) === 'string') return false;
|
|
253
|
-
|
|
254
|
-
let tmpSeparatorIndex = pAddress.indexOf('.');
|
|
255
|
-
|
|
256
|
-
if (tmpSeparatorIndex === -1)
|
|
257
|
-
{
|
|
258
|
-
// Now is the time to set the value in the object
|
|
259
|
-
pObject[pAddress] = pValue;
|
|
260
|
-
return true;
|
|
261
|
-
}
|
|
262
|
-
else
|
|
263
|
-
{
|
|
264
|
-
let tmpSubObjectName = pAddress.substring(0, tmpSeparatorIndex);
|
|
265
|
-
let tmpNewAddress = pAddress.substring(tmpSeparatorIndex+1);
|
|
266
|
-
|
|
267
|
-
// If there is an object property already named for the sub object, but it isn't an object
|
|
268
|
-
// then the system can't set the value in there. Error and abort!
|
|
269
|
-
if (pObject.hasOwnProperty(tmpSubObjectName) && typeof(pObject[tmpSubObjectName]) !== 'object')
|
|
270
|
-
{
|
|
271
|
-
if (!pObject.hasOwnProperty('__ERROR'))
|
|
272
|
-
pObject['__ERROR'] = {};
|
|
273
|
-
// Put it in an error object so data isn't lost
|
|
274
|
-
pObject['__ERROR'][pAddress] = pValue;
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
|
-
else if (pObject.hasOwnProperty(tmpSubObjectName))
|
|
278
|
-
{
|
|
279
|
-
// If there is already a subobject pass that to the recursive thingy
|
|
280
|
-
return this.setValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress, pValue);
|
|
281
|
-
}
|
|
282
|
-
else
|
|
283
|
-
{
|
|
284
|
-
// Create a subobject and then pass that
|
|
285
|
-
pObject[tmpSubObjectName] = {};
|
|
286
|
-
return this.setValueAtAddress(pObject[tmpSubObjectName], tmpNewAddress, pValue);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
setValueAtAddressInContainer(pRecordObject, pFormContainerAddress, pFormContainerIndex, pFormValueAddress, pFormValue)
|
|
292
|
-
{
|
|
293
|
-
// First see if there *is* a container object
|
|
294
|
-
let tmpContainerObject = this.getValueAtAddress(pRecordObject, pFormContainerAddress);
|
|
295
|
-
|
|
296
|
-
if (typeof(pFormContainerAddress) !== 'string') return false;
|
|
297
|
-
|
|
298
|
-
let tmpFormContainerIndex = parseInt(pFormContainerIndex, 10);
|
|
299
|
-
if (isNaN(tmpFormContainerIndex)) return false;
|
|
300
|
-
|
|
301
|
-
if ((typeof(tmpContainerObject) !== 'object') || (!Array.isArray(tmpContainerObject)))
|
|
302
|
-
{
|
|
303
|
-
// Check if there is a value here and we want to store it in the "__OverwrittenData" thing
|
|
304
|
-
tmpContainerObject = [];
|
|
305
|
-
this.setValueAtAddress(pRecordObject, pFormContainerAddress, tmpContainerObject);
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
for (let i = 0; (tmpContainerObject.length + i) <= (tmpFormContainerIndex+1); i++)
|
|
309
|
-
{
|
|
310
|
-
// Add objects to this container until it has enough
|
|
311
|
-
tmpContainerObject.push({});
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// Now set the value *in* the container object
|
|
315
|
-
return this.setValueAtAddress(tmpContainerObject[tmpFormContainerIndex], pFormValueAddress, pFormValue);
|
|
254
|
+
return this.objectAddressResolver.setValueAtAddress(pObject, pAddress, pValue);
|
|
316
255
|
}
|
|
317
256
|
|
|
318
|
-
|
|
319
257
|
// Validate the consistency of an object against the schema
|
|
320
258
|
validate(pObject)
|
|
321
259
|
{
|
|
@@ -332,7 +270,13 @@ class Manyfest
|
|
|
332
270
|
tmpValidationData.Errors.push(`Expected passed in object to be type object but was passed in ${typeof(pObject)}`);
|
|
333
271
|
}
|
|
334
272
|
|
|
335
|
-
|
|
273
|
+
let addValidationError = (pAddress, pErrorMessage) =>
|
|
274
|
+
{
|
|
275
|
+
tmpValidationData.Error = true;
|
|
276
|
+
tmpValidationData.Errors.push(`Element at address "${pAddress}" ${pErrorMessage}.`);
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// Now enumerate through the values and check for anomalies based on the schema
|
|
336
280
|
for (let i = 0; i < this.elementAddresses.length; i++)
|
|
337
281
|
{
|
|
338
282
|
let tmpDescriptor = this.getDescriptor(this.elementAddresses[i]);
|
|
@@ -340,18 +284,144 @@ class Manyfest
|
|
|
340
284
|
|
|
341
285
|
if (typeof(tmpValue) == 'undefined')
|
|
342
286
|
{
|
|
287
|
+
// This will technically mean that `Object.Some.Value = undefined` will end up showing as "missing"
|
|
288
|
+
// TODO: Do we want to do a different message based on if the property exists but is undefined?
|
|
343
289
|
tmpValidationData.MissingElements.push(tmpDescriptor.Address);
|
|
344
|
-
|
|
345
290
|
if (tmpDescriptor.Required || this.options.strict)
|
|
346
291
|
{
|
|
347
|
-
|
|
348
|
-
|
|
292
|
+
addValidationError(tmpDescriptor.Address, 'is flagged REQUIRED but is not set in the object');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Now see if there is a data type specified for this element
|
|
297
|
+
if (tmpDescriptor.DataType)
|
|
298
|
+
{
|
|
299
|
+
let tmpElementType = typeof(tmpValue);
|
|
300
|
+
switch(tmpDescriptor.DataType.toString().trim().toLowerCase())
|
|
301
|
+
{
|
|
302
|
+
case 'string':
|
|
303
|
+
if (tmpElementType != 'string')
|
|
304
|
+
{
|
|
305
|
+
addValidationError(tmpDescriptor.Address, `has a DataType ${tmpDescriptor.DataType} but is of the type ${tmpElementType}`);
|
|
306
|
+
}
|
|
307
|
+
break;
|
|
308
|
+
|
|
309
|
+
case 'number':
|
|
310
|
+
if (tmpElementType != 'number')
|
|
311
|
+
{
|
|
312
|
+
addValidationError(tmpDescriptor.Address, `has a DataType ${tmpDescriptor.DataType} but is of the type ${tmpElementType}`);
|
|
313
|
+
}
|
|
314
|
+
break;
|
|
315
|
+
|
|
316
|
+
case 'integer':
|
|
317
|
+
if (tmpElementType != 'number')
|
|
318
|
+
{
|
|
319
|
+
addValidationError(tmpDescriptor.Address, `has a DataType ${tmpDescriptor.DataType} but is of the type ${tmpElementType}`);
|
|
320
|
+
}
|
|
321
|
+
else
|
|
322
|
+
{
|
|
323
|
+
let tmpValueString = tmpValue.toString();
|
|
324
|
+
if (tmpValueString.indexOf('.') > -1)
|
|
325
|
+
{
|
|
326
|
+
// TODO: Is this an error?
|
|
327
|
+
addValidationError(tmpDescriptor.Address, `has a DataType ${tmpDescriptor.DataType} but has a decimal point in the number.`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
break;
|
|
331
|
+
|
|
332
|
+
case 'float':
|
|
333
|
+
if (tmpElementType != 'number')
|
|
334
|
+
{
|
|
335
|
+
addValidationError(tmpDescriptor.Address, `has a DataType ${tmpDescriptor.DataType} but is of the type ${tmpElementType}`);
|
|
336
|
+
}
|
|
337
|
+
break;
|
|
338
|
+
|
|
339
|
+
case 'DateTime':
|
|
340
|
+
let tmpValueDate = new Date(tmpValue);
|
|
341
|
+
if (tmpValueDate.toString() == 'Invalid Date')
|
|
342
|
+
{
|
|
343
|
+
addValidationError(tmpDescriptor.Address, `has a DataType ${tmpDescriptor.DataType} but is not parsable as a Date by Javascript`);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
default:
|
|
347
|
+
// Check if this is a string, in the default case
|
|
348
|
+
// Note this is only when a DataType is specified and it is an unrecognized data type.
|
|
349
|
+
if (tmpElementType != 'string')
|
|
350
|
+
{
|
|
351
|
+
addValidationError(tmpDescriptor.Address, `has a DataType ${tmpDescriptor.DataType} (which auto-converted to String because it was unrecognized) but is of the type ${tmpElementType}`);
|
|
352
|
+
}
|
|
353
|
+
break;
|
|
349
354
|
}
|
|
350
355
|
}
|
|
351
356
|
}
|
|
352
357
|
|
|
353
358
|
return tmpValidationData;
|
|
354
359
|
}
|
|
360
|
+
|
|
361
|
+
// Returns a default value, or, the default value for the data type (which is overridable with configuration)
|
|
362
|
+
getDefaultValue(pDescriptor)
|
|
363
|
+
{
|
|
364
|
+
if (pDescriptor.hasOwnProperty('Default'))
|
|
365
|
+
{
|
|
366
|
+
return pDescriptor.Default;
|
|
367
|
+
}
|
|
368
|
+
else
|
|
369
|
+
{
|
|
370
|
+
// Default to a null if it doesn't have a type specified.
|
|
371
|
+
// This will ensure a placeholder is created but isn't misinterpreted.
|
|
372
|
+
let tmpDataType = (pDescriptor.hasOwnProperty('DataType')) ? pDescriptor.DataType : 'String';
|
|
373
|
+
if (this.options.defaultValues.hasOwnProperty(tmpDataType))
|
|
374
|
+
{
|
|
375
|
+
return this.options.defaultValues[tmpDataType];
|
|
376
|
+
}
|
|
377
|
+
else
|
|
378
|
+
{
|
|
379
|
+
// give up and return null
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Enumerate through the schema and populate default values if they don't exist.
|
|
386
|
+
populateDefaults(pObject, pOverwriteProperties)
|
|
387
|
+
{
|
|
388
|
+
return this.populateObject(pObject, pOverwriteProperties,
|
|
389
|
+
// This just sets up a simple filter to see if there is a default set.
|
|
390
|
+
(pDescriptor) =>
|
|
391
|
+
{
|
|
392
|
+
return pDescriptor.hasOwnProperty('Default');
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
// Forcefully populate all values even if they don't have defaults.
|
|
397
|
+
// Based on type, this can do unexpected things.
|
|
398
|
+
populateObject(pObject, pOverwriteProperties, fFilter)
|
|
399
|
+
{
|
|
400
|
+
// Automatically create an object if one isn't passed in.
|
|
401
|
+
let tmpObject = (typeof(pObject) === 'object') ? pObject : {};
|
|
402
|
+
// Default to *NOT OVERWRITING* properties
|
|
403
|
+
let tmpOverwriteProperties = (typeof(pOverwriteProperties) == 'undefined') ? false : pOverwriteProperties;
|
|
404
|
+
// This is a filter function, which is passed the schema and allows complex filtering of population
|
|
405
|
+
// The default filter function just returns true, populating everything.
|
|
406
|
+
let tmpFilterFunction = (typeof(fFilter) == 'function') ? fFilter : (pDescriptor) => { return true; };
|
|
407
|
+
|
|
408
|
+
this.elementAddresses.forEach(
|
|
409
|
+
(pAddress) =>
|
|
410
|
+
{
|
|
411
|
+
let tmpDescriptor = this.getDescriptor(pAddress);
|
|
412
|
+
// Check the filter function to see if this is an address we want to set the value for.
|
|
413
|
+
if (tmpFilterFunction(tmpDescriptor))
|
|
414
|
+
{
|
|
415
|
+
// If we are overwriting properties OR the property does not exist
|
|
416
|
+
if (tmpOverwriteProperties || !this.checkAddressExists(tmpObject, pAddress))
|
|
417
|
+
{
|
|
418
|
+
this.setValueAtAddress(tmpObject, pAddress, this.getDefaultValue(tmpDescriptor));
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
return tmpObject;
|
|
424
|
+
}
|
|
355
425
|
};
|
|
356
426
|
|
|
357
427
|
module.exports = Manyfest;
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
{
|
|
2
|
+
"created": 1664830085,
|
|
3
|
+
"d1": "ia600202.us.archive.org",
|
|
4
|
+
"d2": "ia800202.us.archive.org",
|
|
5
|
+
"dir": "/7/items/FrankenberryCountChoculaTevevisionCommercial1971",
|
|
6
|
+
"files": [
|
|
7
|
+
{
|
|
8
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000001.jpg",
|
|
9
|
+
"source": "derivative",
|
|
10
|
+
"format": "Thumbnail",
|
|
11
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
12
|
+
"mtime": "1296336956",
|
|
13
|
+
"size": "838",
|
|
14
|
+
"md5": "e47269cd5a82db9594f265a65785ec12",
|
|
15
|
+
"crc32": "165c668b",
|
|
16
|
+
"sha1": "383303d9546c381267569ad4e33aff691f0bb8c7"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000004.jpg",
|
|
20
|
+
"source": "derivative",
|
|
21
|
+
"format": "Thumbnail",
|
|
22
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
23
|
+
"mtime": "1296336957",
|
|
24
|
+
"size": "6843",
|
|
25
|
+
"md5": "c93fa52000ab4665e69b25c403e11aff",
|
|
26
|
+
"crc32": "9444e6f6",
|
|
27
|
+
"sha1": "716b4f9950b8147f51d3265f9c62ff86451308d5"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000009.jpg",
|
|
31
|
+
"source": "derivative",
|
|
32
|
+
"format": "Thumbnail",
|
|
33
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
34
|
+
"mtime": "1296336957",
|
|
35
|
+
"size": "8388",
|
|
36
|
+
"md5": "30eb3eb4cbbdfa08d531a0a74da7c000",
|
|
37
|
+
"crc32": "be874a9e",
|
|
38
|
+
"sha1": "0c392d777609e967b6022be27edad678c5ae74e2"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000014.jpg",
|
|
42
|
+
"source": "derivative",
|
|
43
|
+
"format": "Thumbnail",
|
|
44
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
45
|
+
"mtime": "1296336958",
|
|
46
|
+
"size": "5993",
|
|
47
|
+
"md5": "4e9ebc3d076bec8cf7dfe76795f8c769",
|
|
48
|
+
"crc32": "912ec98c",
|
|
49
|
+
"sha1": "01dc49c852e1bbb421199450dd902935c62b06de"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000019.jpg",
|
|
53
|
+
"source": "derivative",
|
|
54
|
+
"format": "Thumbnail",
|
|
55
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
56
|
+
"mtime": "1296336958",
|
|
57
|
+
"size": "4951",
|
|
58
|
+
"md5": "59f190f0c5b0a048415b26412860b6dd",
|
|
59
|
+
"crc32": "a70a30b1",
|
|
60
|
+
"sha1": "a284af9757cb24d28f96ec88ec1b1c23a8cea9fe"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000024.jpg",
|
|
64
|
+
"source": "derivative",
|
|
65
|
+
"format": "Thumbnail",
|
|
66
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
67
|
+
"mtime": "1296336959",
|
|
68
|
+
"size": "3383",
|
|
69
|
+
"md5": "be2a908acd563b896e7758b598295148",
|
|
70
|
+
"crc32": "ed467831",
|
|
71
|
+
"sha1": "94c001e72ebc86d837a78c61a004db9ab9d597bd"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000029.jpg",
|
|
75
|
+
"source": "derivative",
|
|
76
|
+
"format": "Thumbnail",
|
|
77
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
78
|
+
"mtime": "1296336960",
|
|
79
|
+
"size": "3503",
|
|
80
|
+
"md5": "c82199d09be07633000fd07b363dd8a3",
|
|
81
|
+
"crc32": "a1fd79cb",
|
|
82
|
+
"sha1": "2bc8e761edb24a441fa5906dda1c424e1f98a47a"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971_archive.torrent",
|
|
86
|
+
"source": "metadata",
|
|
87
|
+
"btih": "de6b371e7cc3c83db1cc08150500753eae533409",
|
|
88
|
+
"mtime": "1542761794",
|
|
89
|
+
"size": "4093",
|
|
90
|
+
"md5": "a275d3b4028cccb5bea8b47a88c838af",
|
|
91
|
+
"crc32": "5ffa7334",
|
|
92
|
+
"sha1": "af8222637b574cba1360d0ea77e231640ffd43c4",
|
|
93
|
+
"format": "Archive BitTorrent"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971_files.xml",
|
|
97
|
+
"source": "metadata",
|
|
98
|
+
"format": "Metadata",
|
|
99
|
+
"md5": "3a7e87b08bed1e203a5858b31352c110"
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971_meta.xml",
|
|
103
|
+
"source": "metadata",
|
|
104
|
+
"format": "Metadata",
|
|
105
|
+
"mtime": "1542761793",
|
|
106
|
+
"size": "1371",
|
|
107
|
+
"md5": "0b9c9bf21b9a26aea43a2f735b404624",
|
|
108
|
+
"crc32": "41077288",
|
|
109
|
+
"sha1": "22e6f2c73bf63072f671d846355da2785db51dbd"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"name": "FrankenberryCountChoculaTevevisionCommercial1971_reviews.xml",
|
|
113
|
+
"source": "original",
|
|
114
|
+
"mtime": "1466898697",
|
|
115
|
+
"size": "620",
|
|
116
|
+
"md5": "260bfba5d696772445dcc7ff6e6d5bdb",
|
|
117
|
+
"crc32": "25ea3229",
|
|
118
|
+
"sha1": "7d541f18fcd5ad9c6e593afe5a80f18771f23b32",
|
|
119
|
+
"format": "Metadata"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"name": "__ia_thumb.jpg",
|
|
123
|
+
"source": "original",
|
|
124
|
+
"mtime": "1539115881",
|
|
125
|
+
"size": "7481",
|
|
126
|
+
"md5": "8cec324fa0016fd77cc04e6a4b2ebb00",
|
|
127
|
+
"crc32": "d9e1b316",
|
|
128
|
+
"sha1": "4dab42952fe0405a3b7f80146636b33d7b1bd01e",
|
|
129
|
+
"format": "Item Tile",
|
|
130
|
+
"rotation": "0"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"name": "frankerberry_countchockula_1971.0001.gif",
|
|
134
|
+
"source": "derivative",
|
|
135
|
+
"format": "Animated GIF",
|
|
136
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
137
|
+
"mtime": "1296336965",
|
|
138
|
+
"size": "101114",
|
|
139
|
+
"md5": "b78a13094030f104900eb996bafe2b7d",
|
|
140
|
+
"crc32": "6650cd8",
|
|
141
|
+
"sha1": "669798c037205cac14f70592deef6f7831b3d4a1"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"name": "frankerberry_countchockula_1971.0001.mpg",
|
|
145
|
+
"source": "original",
|
|
146
|
+
"format": "MPEG2",
|
|
147
|
+
"mtime": "1296335803",
|
|
148
|
+
"size": "31625216",
|
|
149
|
+
"md5": "762ba18b026b85b3f074523e7fcb4db0",
|
|
150
|
+
"crc32": "42347f78",
|
|
151
|
+
"sha1": "41162dc2d1a91b618124c84628d0c231544a02be",
|
|
152
|
+
"length": "31.14",
|
|
153
|
+
"height": "480",
|
|
154
|
+
"width": "640"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
"name": "frankerberry_countchockula_1971.0001.mpg.idx",
|
|
158
|
+
"source": "derivative",
|
|
159
|
+
"format": "Video Index",
|
|
160
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
161
|
+
"mtime": "1296336956",
|
|
162
|
+
"size": "31141",
|
|
163
|
+
"md5": "49423e072726e4ea3cdd8ebdd26c7dfc",
|
|
164
|
+
"crc32": "ae969a68",
|
|
165
|
+
"sha1": "805782cd2d0f9002555816daadf3b8607e621f79"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"name": "frankerberry_countchockula_1971.0001.ogv",
|
|
169
|
+
"source": "derivative",
|
|
170
|
+
"format": "Ogg Video",
|
|
171
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
172
|
+
"mtime": "1296336994",
|
|
173
|
+
"size": "2248166",
|
|
174
|
+
"md5": "f1b933e97ce63594fb28a0a019ff3436",
|
|
175
|
+
"crc32": "a2a0e5e9",
|
|
176
|
+
"sha1": "a6bf0aec9f006baeca37c03f586686ebe685d59b",
|
|
177
|
+
"length": "31.15",
|
|
178
|
+
"height": "300",
|
|
179
|
+
"width": "400"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"name": "frankerberry_countchockula_1971.0001_512kb.mp4",
|
|
183
|
+
"source": "derivative",
|
|
184
|
+
"format": "512Kb MPEG4",
|
|
185
|
+
"original": "frankerberry_countchockula_1971.0001.mpg",
|
|
186
|
+
"mtime": "1296336977",
|
|
187
|
+
"size": "2378677",
|
|
188
|
+
"md5": "a7750839519c61ba3bb99fc66b32011d",
|
|
189
|
+
"crc32": "4dbd37c8",
|
|
190
|
+
"sha1": "3929314c192dec006fac2739bcb4730788e8c068",
|
|
191
|
+
"length": "31.13",
|
|
192
|
+
"height": "240",
|
|
193
|
+
"width": "320"
|
|
194
|
+
}
|
|
195
|
+
],
|
|
196
|
+
"files_count": 17,
|
|
197
|
+
"item_last_updated": 1542761794,
|
|
198
|
+
"item_size": 36431778,
|
|
199
|
+
"metadata": {
|
|
200
|
+
"identifier": "FrankenberryCountChoculaTevevisionCommercial1971",
|
|
201
|
+
"title": "Franken Berry / Count Chocula : Tevevision Commercial 1971",
|
|
202
|
+
"creator": "General Mills",
|
|
203
|
+
"mediatype": "movies",
|
|
204
|
+
"collection": [
|
|
205
|
+
"classic_tv_commercials",
|
|
206
|
+
"television"
|
|
207
|
+
],
|
|
208
|
+
"description": "Count Chocula and Franken Berry were both introduced in 1971. Boo Berry Cereal appeared in 1973 followed by Fruit Brute in 1974. Yummy Mummy appeared more than a decade later in 1988 - completing the the group known as the General Mills Monster Cereals.",
|
|
209
|
+
"subject": "Third Eye Cinema; Classic Television Commercials; animation; cartoons;General Mills",
|
|
210
|
+
"licenseurl": "http://creativecommons.org/publicdomain/mark/1.0/",
|
|
211
|
+
"publicdate": "2011-01-29 21:36:42",
|
|
212
|
+
"addeddate": "2011-01-29 21:35:38",
|
|
213
|
+
"uploader": "bolexman@msn.com",
|
|
214
|
+
"updater": [
|
|
215
|
+
"Bolexman",
|
|
216
|
+
"Bolexman",
|
|
217
|
+
"Jeff Kaplan"
|
|
218
|
+
],
|
|
219
|
+
"updatedate": [
|
|
220
|
+
"2011-01-29 21:45:38",
|
|
221
|
+
"2011-01-29 21:55:46",
|
|
222
|
+
"2011-01-29 23:04:55"
|
|
223
|
+
],
|
|
224
|
+
"sound": "sound",
|
|
225
|
+
"color": "color",
|
|
226
|
+
"runtime": "0:31",
|
|
227
|
+
"backup_location": "ia903608_22",
|
|
228
|
+
"ia_orig__runtime": "31 seconds"
|
|
229
|
+
},
|
|
230
|
+
"reviews": [
|
|
231
|
+
{
|
|
232
|
+
"reviewbody": "Sugar cereal cartoon Karloff and Lugosi argue self-importance pre Lorre ghost. Interesting how kids still know the voices without any idea of the origins.",
|
|
233
|
+
"reviewtitle": "pre booberry",
|
|
234
|
+
"reviewer": "outofthebox",
|
|
235
|
+
"reviewdate": "2016-06-25 23:51:36",
|
|
236
|
+
"createdate": "2016-06-25 23:51:36",
|
|
237
|
+
"stars": "4"
|
|
238
|
+
}
|
|
239
|
+
],
|
|
240
|
+
"server": "ia800202.us.archive.org",
|
|
241
|
+
"uniq": 1957612749,
|
|
242
|
+
"workable_servers": [
|
|
243
|
+
"ia800202.us.archive.org",
|
|
244
|
+
"ia600202.us.archive.org"
|
|
245
|
+
]
|
|
246
|
+
}
|