Commit 4b86c4a1 authored by Romain Courteaud's avatar Romain Courteaud

WIP Jio rewrite.

This is a work in progress commit and all storages are broken.

* Use as much as possible RSVP promise to simplify the code.
* simplify error management: use Error class in case of problem.
* Drop the job management at that point. Such functionnality could be reimplemented as a storage.
* Start to simplify the tests, to speed up debugging.
* Drop requireJS usage, as the goal for now is to make it usage on browser.
* allDocs has to be rewritten to ease storage tree capacity checking. A storage should only implement what it could really do.
* disable attachment management for now.
parent c74c465d
/*jslint indent: 2, maxlen: 80 */
/*global module */
module.exports = function (grunt) { module.exports = function (grunt) {
"use strict"; "use strict";
var LIVERELOAD_PORT, lrSnippet, livereloadMiddleware;
// This is the default port that livereload listens on;
// change it if you configure livereload to use another port.
LIVERELOAD_PORT = 35729;
// lrSnippet is just a function.
// It's a piece of Connect middleware that injects
// a script into the static served html.
lrSnippet = require('connect-livereload')({ port: LIVERELOAD_PORT });
// All the middleware necessary to serve static files.
livereloadMiddleware = function (connect, options) {
return [
// Inject a livereloading script into static files.
lrSnippet,
// Serve static files.
connect.static(options.base),
// Make empty directories browsable.
connect.directory(options.base)
];
};
grunt.loadNpmTasks('grunt-jslint');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-open');
// Project configuration. // Project configuration.
grunt.initConfig({ grunt.initConfig({
pkg: grunt.file.readJSON('package.json'), pkg: grunt.file.readJSON('package.json'),
jslint: { jslint: {
npm: {
src: ['package.json'],
directives: {
maxlen: 100,
indent: 2,
maxerr: 3,
predef: [
'module'
]
}
},
grunt: { grunt: {
src: ['Gruntfile.js'], src: ['Gruntfile.js'],
options: { directives: {
errorsOnly: true es5: true,
maxlen: 80,
indent: 2,
maxerr: 3,
predef: [
'module',
'require'
]
} }
}, },
jio: { jio: {
src: ['src/jio/**/*.js'], src: ['src/jio.js', 'src/jio/**/*.js', 'src/jio/*.js'],
exclude: ['src/jio/intro.js', 'src/jio/outro.js'], exclude: ['src/jio/intro.js', 'src/jio/outro.js'],
options: { directives: {
errorsOnly: true maxlen: 80,
indent: 2,
maxerr: 3,
nomen: true
} }
}, },
jio_storages: { jio_storages: {
src: ['src/jio.storage/**/*.js'], src: ['src/jio.storage/**/*.js'],
options: { directives: {
errorsOnly: true maxlen: 80,
indent: 2,
maxerr: 3,
predef: [
'define',
'exports',
'require',
'window',
'jIO',
'complex_queries'
]
} }
}, },
jiodate: { jiodate: {
src: ['src/jio.date/jiodate.js'] src: ['src/jio.date/jiodate.js'],
directives: {
maxlen: 80,
indent: 2,
maxerr: 3,
predef: [
'jIO'
]
},
}, },
tests: { tests: {
src: ['test/**/*.js'], src: ['test/**/*.js'],
options: { directives: {
errorsOnly: true maxlen: 80,
} indent: 2,
maxerr: 3,
predef: [
'RSVP',
'QUnit',
'jIO'
]
},
}, },
queries: { queries: {
src: ['src/queries/core/**/*.js'], src: ['src/queries/core/**/*.js'],
...@@ -47,19 +120,40 @@ module.exports = function (grunt) { ...@@ -47,19 +120,40 @@ module.exports = function (grunt) {
options: { options: {
errorsOnly: true errorsOnly: true
} }
} },
examples: {
src: ['examples/*.js'],
directives: {
maxlen: 80,
indent: 2,
maxerr: 3,
predef: [
'window',
'RSVP',
'rJS',
'QUnit',
'jIO'
]
},
},
}, },
concat: { concat: {
options: {
separator: ';'
},
jio: { jio: {
// duplicate files are ignored // duplicate files are ignored
src: [ src: [
'src/jio/intro.js', // 'node_modules/moment/moment.js',
'lib/moment/moment-2.5.0.js',
// core // 'src/*.js',
'src/jio/core/globals.js', // 'src/jio/intro.js',
'src/jio/core/util.js', //
'src/jio/core/**/*.js', // // core
'src/jio/features/**/*.js', // 'src/jio/core/globals.js',
// 'src/jio/core/util.js',
// 'src/jio/core/**/*.js',
// 'src/jio/features/**/*.js',
// queries // queries
'src/queries/core/globals.js', 'src/queries/core/globals.js',
...@@ -70,9 +164,19 @@ module.exports = function (grunt) { ...@@ -70,9 +164,19 @@ module.exports = function (grunt) {
'src/queries/core/tools.js', 'src/queries/core/tools.js',
'src/queries/core/**/*.js', 'src/queries/core/**/*.js',
'src/jio/outro.js' 'src/jio.date/*.js',
// 'src/jio/outro.js',
'src/jio.js',
'src/jio.storage/localstorage.js',
'src/jio.storage/davstorage.js',
'src/jio.storage/indexeddbstorage.js',
'src/jio.storage/unionstorage.js',
'src/jio.storage/querystorage.js'
], ],
dest: 'jio.js' dest: 'dist/<%= pkg.name %>-<%= pkg.version %>.js'
// dest: 'jio.js'
} }
}, },
uglify: { uglify: {
...@@ -81,37 +185,91 @@ module.exports = function (grunt) { ...@@ -81,37 +185,91 @@ module.exports = function (grunt) {
'<%= grunt.template.today("yyyy-mm-dd") %> */\n' '<%= grunt.template.today("yyyy-mm-dd") %> */\n'
}, },
jio: { jio: {
src: 'jio.js', // '<%= pkg.name %>.js' src: "<%= concat.jio.dest %>",
dest: 'jio.min.js', dest: "dist/<%= pkg.name %>-<%= pkg.version %>.min.js"
// },
// jio: {
// src: 'jio.js', // '<%= pkg.name %>.js'
// dest: 'jio.min.js',
// options: {
// sourceMap: "jio.min.map"
// }
// },
// jiodate: {
// src: 'src/jio.date/jiodate.js',
// dest: 'jiodate.min.js',
// options: {
// sourceMap: "jiodate.min.map"
// }
}
},
copy: {
latest: {
files: [{
src: '<%= uglify.jio.src %>',
dest: "dist/<%= pkg.name %>-latest.js"
}, {
src: '<%= uglify.jio.dest %>',
dest: "dist/<%= pkg.name %>-latest.min.js"
}]
}
},
qunit: {
// grunt doesn't like requirejs
files: ['test/tests.html']
},
watch: {
src: {
files: [
'<%= jslint.npm.src %>',
'<%= jslint.grunt.src %>',
'<%= jslint.jio.src %>',
'<%= jslint.jiodate.src %>',
'<%= jslint.jio_storages.src %>',
'<%= jslint.tests.src %>',
'<%= jslint.queries.src %>',
'<%= qunit.files %>',
'test/**/*.js',
'examples/*'
],
tasks: ['default'],
options: { options: {
sourceMap: "jio.min.map" livereload: LIVERELOAD_PORT
} }
}, }
jiodate: { },
src: 'src/jio.date/jiodate.js',
dest: 'jiodate.min.js',
connect: {
client: {
options: { options: {
sourceMap: "jiodate.min.map" port: 9000,
base: '.',
directory: '.',
middleware: livereloadMiddleware
} }
} }
}, },
qunit: {
// grunt doesn't like requirejs open: {
files: ['test/tests.html'], all: {
options: { // Gets the port from the connect configuration
timeout: 30000 // if no test occurs for 30 seconds, then timeout path: 'http://localhost:' +
'<%= connect.client.options.port%>/test/tests.html'
} }
} }
});
grunt.loadNpmTasks('grunt-jslint');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-qunit');
grunt.registerTask('default', ['jslint', 'concat', 'uglify', 'qunit']); });
grunt.registerTask('default', ['all']);
grunt.registerTask('all', ['lint', 'build']);
grunt.registerTask('lint', ['jslint']); grunt.registerTask('lint', ['jslint']);
grunt.registerTask('build', ['concat', 'uglify']); grunt.registerTask('test', ['qunit']);
grunt.registerTask('test', ['jslint', 'qunit']); grunt.registerTask('server', ['connect:client', 'watch']);
grunt.registerTask('build', ['concat', 'uglify', 'copy']);
}; };
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jIO Coverage Scenario</title>
<link rel="stylesheet" href="../node_modules/grunt-contrib-qunit/test/libs/qunit.css" type="text/css" media="screen"/>
<script src="../node_modules/grunt-contrib-qunit/test/libs/qunit.js" type="text/javascript"></script>
<script src="../node_modules/rsvp/dist/rsvp-2.0.4.js"></script>
<script src="../node_modules/renderjs/dist/renderjs-latest.js"></script>
<script src="../dist/jio-latest.js"></script>
<script src="scenario.js"></script>
</head>
<body>
<h1 id="qunit-header">jIO Coverage Scenario</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture">test markup, will be hidden</div>
</body>
</html>
/*global console, btoa*/
/*jslint nomen: true*/
(function (window, QUnit, jIO, rJS) {
"use strict";
var test = QUnit.test,
equal = QUnit.equal,
expect = QUnit.expect,
ok = QUnit.ok,
stop = QUnit.stop,
start = QUnit.start,
deepEqual = QUnit.deepEqual;
rJS(window)
.ready(function (g) {
return g.run({
"type": "indexeddb",
"database": "test"
});
})
.ready(function (g) {
return g.run({
"type": "local"
});
})
.ready(function (g) {
return g.run({
"type": "dav"
});
})
.declareMethod('run', function (jio_options) {
test('Test "' + jio_options.type + '"scenario', function () {
var jio;
stop();
expect(3);
try {
jio = jIO.createJIO(jio_options);
} catch (error) {
console.error(error.stack);
console.error(error);
throw error;
}
// Try to fetch inexistent document
jio.get({"_id": "inexistent"})
.fail(function (error) {
equal(error.status_code, 404, "404 if inexistent");
// Post a document without ID
return jio.post({"title": "I don't have ID"});
})
.then(function (doc_id) {
ok(doc_id, "Document without ID created");
// Fetch the newly created document
return jio.get({"_id": doc_id});
})
.then(function (doc) {
var doc_id = doc._id;
delete doc._id;
deepEqual(doc, {"title": "I don't have ID"},
"Document correctly fetched");
// Remove the doc
return jio.remove({"_id": doc_id});
})
.then(function (doc_id) {
ok(doc_id, "Document removed");
})
.fail(function (error) {
console.error(error.stack);
console.error(error);
ok(false, error);
})
.always(function () {
start();
});
});
});
}(window, QUnit, jIO, rJS));
This diff is collapsed.
/**
* QUnit v1.13.0pre-780a7a98935a907a2e4c57777b3bbe28ea0ea1ec 2013-07-26 - A JavaScript Unit Testing Framework
*
* http://qunitjs.com
*
* Copyright 2012 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
/** Font Family and Sizes */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
}
#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
#qunit-tests { font-size: smaller; }
/** Resets */
#qunit-tests, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult, #qunit-modulefilter {
margin: 0;
padding: 0;
}
/** Header */
#qunit-header {
padding: 0.5em 0 0.5em 1em;
color: #8699a4;
background-color: #0d3349;
font-size: 1.5em;
line-height: 1em;
font-weight: normal;
border-radius: 5px 5px 0 0;
-moz-border-radius: 5px 5px 0 0;
-webkit-border-top-right-radius: 5px;
-webkit-border-top-left-radius: 5px;
}
#qunit-header a {
text-decoration: none;
color: #c2ccd1;
}
#qunit-header a:hover,
#qunit-header a:focus {
color: #fff;
}
#qunit-testrunner-toolbar label {
display: inline-block;
padding: 0 .5em 0 .1em;
}
#qunit-banner {
height: 5px;
}
#qunit-testrunner-toolbar {
padding: 0.5em 0 0.5em 2em;
color: #5E740B;
background-color: #eee;
overflow: hidden;
}
#qunit-userAgent {
padding: 0.5em 0 0.5em 2.5em;
background-color: #2b81af;
color: #fff;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
}
#qunit-modulefilter-container {
float: right;
}
/** Tests: Pass/Fail */
#qunit-tests {
list-style-position: inside;
}
#qunit-tests li {
padding: 0.4em 0.5em 0.4em 2.5em;
border-bottom: 1px solid #fff;
list-style-position: inside;
}
#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
display: none;
}
#qunit-tests li strong {
cursor: pointer;
}
#qunit-tests li a {
padding: 0.5em;
color: #c2ccd1;
text-decoration: none;
}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
}
#qunit-tests li .runtime {
float: right;
font-size: smaller;
}
.qunit-assert-list {
margin-top: 0.5em;
padding: 0.5em;
background-color: #fff;
border-radius: 5px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
}
.qunit-collapsed {
display: none;
}
#qunit-tests table {
border-collapse: collapse;
margin-top: .2em;
}
#qunit-tests th {
text-align: right;
vertical-align: top;
padding: 0 .5em 0 0;
}
#qunit-tests td {
vertical-align: top;
}
#qunit-tests pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
}
#qunit-tests del {
background-color: #e0f2be;
color: #374e0c;
text-decoration: none;
}
#qunit-tests ins {
background-color: #ffcaca;
color: #500;
text-decoration: none;
}
/*** Test Counts */
#qunit-tests b.counts { color: black; }
#qunit-tests b.passed { color: #5E740B; }
#qunit-tests b.failed { color: #710909; }
#qunit-tests li li {
padding: 5px;
background-color: #fff;
border-bottom: none;
list-style-position: inside;
}
/*** Passing Styles */
#qunit-tests li li.pass {
color: #3c510c;
background-color: #fff;
border-left: 10px solid #C6E746;
}
#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
#qunit-tests .pass .test-name { color: #366097; }
#qunit-tests .pass .test-actual,
#qunit-tests .pass .test-expected { color: #999999; }
#qunit-banner.qunit-pass { background-color: #C6E746; }
/*** Failing Styles */
#qunit-tests li li.fail {
color: #710909;
background-color: #fff;
border-left: 10px solid #EE5757;
white-space: pre;
}
#qunit-tests > li:last-child {
border-radius: 0 0 5px 5px;
-moz-border-radius: 0 0 5px 5px;
-webkit-border-bottom-right-radius: 5px;
-webkit-border-bottom-left-radius: 5px;
}
#qunit-tests .fail { color: #000000; background-color: #EE5757; }
#qunit-tests .fail .test-name,
#qunit-tests .fail .module-name { color: #000000; }
#qunit-tests .fail .test-actual { color: #EE5757; }
#qunit-tests .fail .test-expected { color: green; }
#qunit-banner.qunit-fail { background-color: #EE5757; }
/** Result */
#qunit-testresult {
padding: 0.5em 0.5em 0.5em 2.5em;
color: #2b81af;
background-color: #D2E0E6;
border-bottom: 1px solid white;
}
#qunit-testresult .module-name {
font-weight: bold;
}
/** Fixture */
#qunit-fixture {
position: absolute;
top: -10000px;
left: -10000px;
width: 1000px;
height: 1000px;
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/**
* sinon-qunit 1.0.0, 2010/12/09
*
* @author Christian Johansen (christian@cjohansen.no)
*
* (The BSD License)
*
* Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Christian Johansen nor the names of his contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*global sinon, QUnit, test*/
sinon.assert.fail = function (msg) {
QUnit.ok(false, msg);
};
sinon.assert.pass = function (assertion) {
QUnit.ok(true, assertion);
};
sinon.config = {
injectIntoThis: true,
injectInto: null,
properties: ["spy", "stub", "mock", "clock", "sandbox"],
useFakeTimers: false,
useFakeServer: false
};
(function (global) {
var qTest = QUnit.test;
QUnit.test = global.test = function (testName, expected, callback, async) {
if (arguments.length === 2) {
callback = expected;
expected = null;
}
return qTest(testName, expected, sinon.test(callback), async);
};
}(this));
This diff is collapsed.
{ {
"name": "jio", "name": "jio",
"version": "v2.0.0", "version": "v3.0.0",
"license": "LGPLv3", "license": "LGPLv3",
"author": "Nexedi SA", "author": "Nexedi SA",
"contributors": [ "contributors": [
...@@ -14,7 +14,9 @@ ...@@ -14,7 +14,9 @@
"test": "test" "test": "test"
}, },
"scripts": { "scripts": {
"test": "grunt test" "test": "./node_modules/.bin/grunt test",
"lint": "./node_modules/.bin/grunt lint",
"prepublish": "./node_modules/.bin/grunt build"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
...@@ -26,13 +28,25 @@ ...@@ -26,13 +28,25 @@
"output", "output",
"cloud" "cloud"
], ],
"dependencies": {
"rsvp": "git+http://git.erp5.org/repos/rsvp.js.git",
"moment": "2.8.3"
},
"devDependencies": { "devDependencies": {
"renderjs": "git+http://git.erp5.org/repos/renderjs.git",
"jscc-node": "0.3.x", "jscc-node": "0.3.x",
"grunt": "0.4.x", "grunt": "0.4.x",
"grunt-cli": "~0.1.11",
"grunt-contrib-concat": "0.3.x", "grunt-contrib-concat": "0.3.x",
"grunt-contrib-copy": "~0.4.1",
"grunt-contrib-uglify": "0.2.x", "grunt-contrib-uglify": "0.2.x",
"grunt-contrib-qunit": "0.2.x", "grunt-contrib-qunit": "~0.3.0",
"grunt-jslint": "1.0.x" "grunt-contrib-watch": "~0.5.3",
"grunt-jslint": "~1.0.0",
"sinon": "~1.7.3",
"connect-livereload": "~0.3.0",
"grunt-open": "~0.2.2",
"grunt-contrib-connect": "~0.5.0"
}, },
"engines": { "engines": {
"npm": ">=1.3" "npm": ">=1.3"
......
This diff is collapsed.
This diff is collapsed.
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global jIO: true, sjcl: true, $: true, setTimeout: true */ /*global jIO: true, sjcl: true, $: true, setTimeout: true */
jIO.addStorageType('crypt', function (spec, my) { jIO.addStorage('crypt', function (spec, my) {
/*jslint todo: true*/ /*jslint todo: true*/
spec = spec || {}; spec = spec || {};
var that = my.basicStorage(spec, my), var that = my.basicStorage(spec, my),
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*jslint indent: 2, maxlen: 80, nomen: true, sloppy: true */
/*global EventEmitter, deepClone, inherits, exports */
/*global enableRestAPI, enableRestParamChecker, enableJobMaker, enableJobRetry,
enableJobReference, enableJobChecker, enableJobQueue, enableJobRecovery,
enableJobTimeout, enableJobExecuter */
function JIO(storage_spec, options) {
JIO.super_.call(this);
var shared = new EventEmitter();
shared.storage_spec = deepClone(storage_spec);
if (options === undefined) {
options = {};
} else if (typeof options !== 'object' || Array.isArray(options)) {
throw new TypeError("JIO(): Optional argument 2 is not of type 'object'");
}
enableRestAPI(this, shared, options);
enableRestParamChecker(this, shared, options);
enableJobMaker(this, shared, options);
enableJobReference(this, shared, options);
enableJobRetry(this, shared, options);
enableJobTimeout(this, shared, options);
enableJobChecker(this, shared, options);
enableJobQueue(this, shared, options);
enableJobRecovery(this, shared, options);
enableJobExecuter(this, shared, options);
shared.emit('load');
}
inherits(JIO, EventEmitter);
JIO.createInstance = function (storage_spec, options) {
return new JIO(storage_spec, options);
};
exports.JIO = JIO;
exports.createJIO = JIO.createInstance;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
window.jIO = {};
module(window.jIO, RSVP, {hex_sha256: hex_sha256});
}(['exports', 'rsvp', 'sha256'], function (exports, RSVP, sha256) {
"use strict";
var hex_sha256 = sha256.hex_sha256;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment