diff --git a/.gitignore b/.gitignore index 16891e68..701a4063 100755 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ uploads/* !uploads/README.md VCAP_SERVICES.json run.sh + +.env.js diff --git a/README.md b/README.md index 0c1da368..08684a4c 100755 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Visual Recognition Nodejs Starter Application -The [IBM Watson Visual Recognition service][visual_recognition_service] analyzes the visual content of images to understand the scene without any input text describing +[Visual Recognition][visual_recognition_service] partnered with [Alchemy Vision](www.alchemyapi.com/products/alchemyvision), allows you to derive insights from an image based on its visual content. You can organize image libraries, understand an individual image, and create custom classifiers for specific results that are tailored to your needs. Give it a try! Click the button below to fork into IBM DevOps Services and deploy your own copy of this application on Bluemix. @@ -37,21 +37,26 @@ applications: $ cf create-service visual_recognition free visual-recognition-service ``` -6. Push it live! +6. Create the Alchemy service in Bluemix or copy your existing key into `ALCHEMY_KEY` in `app.js` + ```sh + $ cf create-service alchemy_api free alchemy-service + ``` + +7. Push it live! ```sh $ cf push ``` - + 7. Optional Security and Performance enhancements Set `NODE_ENV=production` to enable view caching and other performance enhancements: - + ```sh $ cf set-env NODE_ENV production ``` - + Set `SECURE_EXPRESS=1` to enable rate-limiting, HTTPS-only, and several other security features: - + ```sh $ cf set-env SECURE_EXPRESS 1 ``` diff --git a/app.js b/app.js index 296c731d..a03f2a25 100755 --- a/app.js +++ b/app.js @@ -16,6 +16,17 @@ 'use strict'; +try { + var env = require('./.env.js'); + console.log('loading .env.js'); + for (var key in env) { + if (!(key in process.env)) + process.env[key] = env[key]; + } +} catch(ex) { + console.log('.env.js not found'); +} + var express = require('express'), app = express(), fs = require('fs'), @@ -26,6 +37,7 @@ var express = require('express'), request = require('request'), datasets = require('./public/data/datasets.json'), zipUtils = require('./config/zip-utils'), + uuid = require('uuid'), watson = require('watson-developer-cloud'); @@ -42,8 +54,24 @@ var visualRecognition = watson.visual_recognition({ version_date:'2015-12-02' }); +var alchemyVision = watson.alchemy_vision({ + api_key: process.env.ALCHEMY_KEY || '' +}); + app.get('/', function(req, res) { - res.render('index', datasets); + res.render('use', datasets); +}); + +app.get('/use', function(req, res) { + res.render('use', datasets); +}); + +app.get('/train', function(req, res) { + res.render('train', datasets); +}); + +app.get('/test', function(req, res) { + res.render('test', datasets); }); /** @@ -67,6 +95,36 @@ function filterUserCreatedClassifier(result, classifier_ids) { } return result; } + +/** + * Normalize Alchemy Vision results + * @param {Object} Alchemy vision result + * @return {Object} Visual Recognition result + */ +function normalizeResult(item) { + var result = { + name: item.text || 'Unknown', + score: parseFloat(item.score || '0') + }; + return result; +} + +function noTags(tag) { + return tag.name !== 'NO_TAGS'; +} +/** + * Formats Alchemy Vision results to match the Watson Vision format + * @param {Object} result The result of calling 'classify()' + * @return {Object} The formatted 'result' + */ +function formatAlchemyVisionResults(results) { + return { + images: [{ + scores: results.imageKeywords.map(normalizeResult).filter(noTags) + }] + }; +} + /** * Creates a classifier * @param req.body.positives Array of base64 or relative images @@ -138,6 +196,12 @@ app.post('/api/classify', app.upload.single('images_file'), function(req, res, n if (req.file) { // file image file = fs.createReadStream(req.file.path); + } else if (req.body.image_data) { + // write the base64 image to a temp file + var resource = zipUtils.parseBase64Image(req.body.image_data); + var temp = './uploads/' + uuid.v1() + '.' + resource.type; + fs.writeFileSync(temp, resource.data); + file = fs.createReadStream(temp); } else if (req.body.url && validator.isURL(req.body.url)) { // web image file = request(req.body.url.split('?')[0]); @@ -149,23 +213,33 @@ app.post('/api/classify', app.upload.single('images_file'), function(req, res, n return next({ error: 'Malformed URL', code: 400 }); } - var params = { - images_file: file - }; + if (req.query.classifier_id) { + var vparams = { + images_file: file, + classifier_ids: [req.query.classifier_id] + }; - if (req.query.classifier_id) - params.classifier_ids = [req.query.classifier_id]; + visualRecognition.classify(vparams, function(err, results) { + if (req.file || req.body.image_data) // delete the recognized file + fs.unlink(file.path); - visualRecognition.classify(params, function(err, results) { - // delete the recognized file - if (req.file) - fs.unlink(file.path); - - if (err) - return next(err); - else - res.json(filterUserCreatedClassifier(results, params.classifier_ids)); - }); + if (err) + return next(err); + else + res.json(filterUserCreatedClassifier(results, vparams.classifier_ids)); + }); + } else { + alchemyVision.getImageKeywords({ image: file}, function (err, results) { + // delete the recognized file + if (req.file || req.body.image_data) + fs.unlink(file.path); + + if (err) + return next(err); + else + res.json(formatAlchemyVisionResults(results)); + }); + } }); // error-handler settings diff --git a/config/security.js b/config/security.js index 1c02b023..c09f2eb8 100644 --- a/config/security.js +++ b/config/security.js @@ -28,7 +28,7 @@ module.exports = function (app) { app.use(secure()); // 2. helmet with defaults - app.use(helmet()); + app.use(helmet({ cacheControl: false })); // 3. rate-limit to /api/ app.use('/api/', rateLimit({ diff --git a/config/zip-utils.js b/config/zip-utils.js index 2fc29804..013da1e7 100644 --- a/config/zip-utils.js +++ b/config/zip-utils.js @@ -38,6 +38,7 @@ function parseBase64Image(imageString) { resource.data = new Buffer(matches[2], 'base64'); return resource; } +module.exports.parseBase64Image = parseBase64Image; /** * Archives an image uning the @param archive module @@ -61,7 +62,6 @@ function archiveImage(archive, image) { } } - /** * Creates a zip file with the images array * @param images The images to zip diff --git a/package.json b/package.json index a16fe909..d28c1205 100644 --- a/package.json +++ b/package.json @@ -29,19 +29,19 @@ "start": "node app.js" }, "dependencies": { - "archiver": "^0.16.0", + "archiver": "^0.21.0", "async": "^1.5.0", - "body-parser": "^1.13.2", - "express": "^4.12.2", - "express-rate-limit": "^2.0.2", + "body-parser": "^1.15.0", + "express": "^4.13.4", + "express-rate-limit": "^2.1.0", "express-secure-only": "^0.2.1", - "find-remove": "^0.2.8", + "find-remove": "^0.2.10", "helmet": "^1.3.0", "jade": "^1.11.0", "multer": "^1.1.0", - "request": "^2.65.0", + "request": "^2.69.0", "uuid": "^2.0.1", - "validator": "^4.7.0", - "watson-developer-cloud": "^1.0.6" + "validator": "^5.1.0", + "watson-developer-cloud": "^1.3.1" } } \ No newline at end of file diff --git a/public/css/style.css b/public/css/style.css index 7d40d380..879771ea 100755 --- a/public/css/style.css +++ b/public/css/style.css @@ -1153,6 +1153,10 @@ pre[class*=" language-"] { .tab-views--tab-pane { margin-top: 2rem; } +.use--header { + margin-top: 1rem; + margin-bottom: 1rem; } + .use--example-radio { display: none; } @@ -1349,7 +1353,8 @@ pre[class*=" language-"] { .use--output-note { margin-top: 2rem; - color: #777677; } + color: #777677; + font-size: 0.9rem; } .use--hr { border-top-width: 3px; } @@ -1978,1874 +1983,6 @@ pre[class*=" language-"] { visibility: visible; opacity: 1; } -.style-tile--title { - text-align: center; } - -.style-tile--color { - width: 140px; - height: 140px; - margin: 0rem; - display: inline-block; - word-break: break-word; - padding: 0.5rem; - vertical-align: middle; } - .style-tile--color:nth-of-type(1) { - background-color: #c0e6ff; - color: #000; } - .style-tile--color:nth-of-type(1):after { - content: "color('blue', 10)|#c0e6ff"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(2) { - background-color: #7cc7ff; - color: #000; } - .style-tile--color:nth-of-type(2):after { - content: "color('blue', 20)|#7cc7ff"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(3) { - background-color: #5aaafa; - color: #000; } - .style-tile--color:nth-of-type(3):after { - content: "color('blue', 30)|#5aaafa"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(4) { - background-color: #5596e6; - color: #000; } - .style-tile--color:nth-of-type(4):after { - content: "color('blue', 40)|#5596e6"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(5) { - background-color: #4178be; - color: #000; } - .style-tile--color:nth-of-type(5):after { - content: "color('blue', 50)|#4178be"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(6) { - background-color: #325c80; - color: #fff; } - .style-tile--color:nth-of-type(6):after { - content: "color('blue', 60)|#325c80"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(7) { - background-color: #264a60; - color: #fff; } - .style-tile--color:nth-of-type(7):after { - content: "color('blue', 70)|#264a60"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(8) { - background-color: #1d3649; - color: #fff; } - .style-tile--color:nth-of-type(8):after { - content: "color('blue', 80)|#1d3649"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(9) { - background-color: #152935; - color: #fff; } - .style-tile--color:nth-of-type(9):after { - content: "color('blue', 90)|#152935"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(10) { - background-color: #010205; - color: #fff; } - .style-tile--color:nth-of-type(10):after { - content: "color('blue', 100)|#010205"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(11) { - background-color: #c8f08f; - color: #000; } - .style-tile--color:nth-of-type(11):after { - content: "color('green', 10)|#c8f08f"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(12) { - background-color: #b4e051; - color: #000; } - .style-tile--color:nth-of-type(12):after { - content: "color('green', 20)|#b4e051"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(13) { - background-color: #8cd211; - color: #fff; } - .style-tile--color:nth-of-type(13):after { - content: "color('green', 30)|#8cd211"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(14) { - background-color: #6eb400; - color: #fff; } - .style-tile--color:nth-of-type(14):after { - content: "color('green', 40)|#6eb400"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(15) { - background-color: #4b8400; - color: #fff; } - .style-tile--color:nth-of-type(15):after { - content: "color('green', 50)|#4b8400"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(16) { - background-color: #2d660a; - color: #fff; } - .style-tile--color:nth-of-type(16):after { - content: "color('green', 60)|#2d660a"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(17) { - background-color: #144d14; - color: #fff; } - .style-tile--color:nth-of-type(17):after { - content: "color('green', 70)|#144d14"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(18) { - background-color: #0a3c02; - color: #fff; } - .style-tile--color:nth-of-type(18):after { - content: "color('green', 80)|#0a3c02"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(19) { - background-color: #0c2808; - color: #fff; } - .style-tile--color:nth-of-type(19):after { - content: "color('green', 90)|#0c2808"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(20) { - background-color: #010200; - color: #fff; } - .style-tile--color:nth-of-type(20):after { - content: "color('green', 100)|#010200"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(21) { - background-color: #a7fae6; - color: #000; } - .style-tile--color:nth-of-type(21):after { - content: "color('teal', 10)|#a7fae6"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(22) { - background-color: #6eedd8; - color: #000; } - .style-tile--color:nth-of-type(22):after { - content: "color('teal', 20)|#6eedd8"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(23) { - background-color: #41d6c3; - color: #000; } - .style-tile--color:nth-of-type(23):after { - content: "color('teal', 30)|#41d6c3"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(24) { - background-color: #00b4a0; - color: #fff; } - .style-tile--color:nth-of-type(24):after { - content: "color('teal', 40)|#00b4a0"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(25) { - background-color: #008571; - color: #fff; } - .style-tile--color:nth-of-type(25):after { - content: "color('teal', 50)|#008571"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(26) { - background-color: #006d5d; - color: #fff; } - .style-tile--color:nth-of-type(26):after { - content: "color('teal', 60)|#006d5d"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(27) { - background-color: #005448; - color: #fff; } - .style-tile--color:nth-of-type(27):after { - content: "color('teal', 70)|#005448"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(28) { - background-color: #003c32; - color: #fff; } - .style-tile--color:nth-of-type(28):after { - content: "color('teal', 80)|#003c32"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(29) { - background-color: #012b22; - color: #fff; } - .style-tile--color:nth-of-type(29):after { - content: "color('teal', 90)|#012b22"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(30) { - background-color: #000202; - color: #fff; } - .style-tile--color:nth-of-type(30):after { - content: "color('teal', 100)|#000202"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(31) { - background-color: #eed2ff; - color: #000; } - .style-tile--color:nth-of-type(31):after { - content: "color('purple', 10)|#eed2ff"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(32) { - background-color: #d7aaff; - color: #000; } - .style-tile--color:nth-of-type(32):after { - content: "color('purple', 20)|#d7aaff"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(33) { - background-color: #ba8ff7; - color: #000; } - .style-tile--color:nth-of-type(33):after { - content: "color('purple', 30)|#ba8ff7"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(34) { - background-color: #af6ee8; - color: #000; } - .style-tile--color:nth-of-type(34):after { - content: "color('purple', 40)|#af6ee8"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(35) { - background-color: #9855d4; - color: #000; } - .style-tile--color:nth-of-type(35):after { - content: "color('purple', 50)|#9855d4"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(36) { - background-color: #734098; - color: #fff; } - .style-tile--color:nth-of-type(36):after { - content: "color('purple', 60)|#734098"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(37) { - background-color: #562f72; - color: #fff; } - .style-tile--color:nth-of-type(37):after { - content: "color('purple', 70)|#562f72"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(38) { - background-color: #412356; - color: #fff; } - .style-tile--color:nth-of-type(38):after { - content: "color('purple', 80)|#412356"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(39) { - background-color: #311a41; - color: #fff; } - .style-tile--color:nth-of-type(39):after { - content: "color('purple', 90)|#311a41"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(40) { - background-color: #030103; - color: #fff; } - .style-tile--color:nth-of-type(40):after { - content: "color('purple', 100)|#030103"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(41) { - background-color: #ffd2ff; - color: #000; } - .style-tile--color:nth-of-type(41):after { - content: "color('magenta', 10)|#ffd2ff"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(42) { - background-color: #ff9eee; - color: #000; } - .style-tile--color:nth-of-type(42):after { - content: "color('magenta', 20)|#ff9eee"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(43) { - background-color: #ff71d4; - color: #000; } - .style-tile--color:nth-of-type(43):after { - content: "color('magenta', 30)|#ff71d4"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(44) { - background-color: #ff3ca0; - color: #000; } - .style-tile--color:nth-of-type(44):after { - content: "color('magenta', 40)|#ff3ca0"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(45) { - background-color: #db2780; - color: #000; } - .style-tile--color:nth-of-type(45):after { - content: "color('magenta', 50)|#db2780"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(46) { - background-color: #a6266e; - color: #fff; } - .style-tile--color:nth-of-type(46):after { - content: "color('magenta', 60)|#a6266e"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(47) { - background-color: #7c1c58; - color: #fff; } - .style-tile--color:nth-of-type(47):after { - content: "color('magenta', 70)|#7c1c58"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(48) { - background-color: #601146; - color: #fff; } - .style-tile--color:nth-of-type(48):after { - content: "color('magenta', 80)|#601146"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(49) { - background-color: #3a0b2e; - color: #fff; } - .style-tile--color:nth-of-type(49):after { - content: "color('magenta', 90)|#3a0b2e"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(50) { - background-color: #040102; - color: #fff; } - .style-tile--color:nth-of-type(50):after { - content: "color('magenta', 100)|#040102"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(51) { - background-color: #ffd2dd; - color: #000; } - .style-tile--color:nth-of-type(51):after { - content: "color('red', 10)|#ffd2dd"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(52) { - background-color: #ffa5b4; - color: #000; } - .style-tile--color:nth-of-type(52):after { - content: "color('red', 20)|#ffa5b4"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(53) { - background-color: #ff7d87; - color: #000; } - .style-tile--color:nth-of-type(53):after { - content: "color('red', 30)|#ff7d87"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(54) { - background-color: #ff5050; - color: #000; } - .style-tile--color:nth-of-type(54):after { - content: "color('red', 40)|#ff5050"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(55) { - background-color: #e71d32; - color: #000; } - .style-tile--color:nth-of-type(55):after { - content: "color('red', 50)|#e71d32"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(56) { - background-color: #ad1625; - color: #fff; } - .style-tile--color:nth-of-type(56):after { - content: "color('red', 60)|#ad1625"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(57) { - background-color: #8c101c; - color: #fff; } - .style-tile--color:nth-of-type(57):after { - content: "color('red', 70)|#8c101c"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(58) { - background-color: #6e0a1e; - color: #fff; } - .style-tile--color:nth-of-type(58):after { - content: "color('red', 80)|#6e0a1e"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(59) { - background-color: #4c0a17; - color: #fff; } - .style-tile--color:nth-of-type(59):after { - content: "color('red', 90)|#4c0a17"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(60) { - background-color: #040001; - color: #fff; } - .style-tile--color:nth-of-type(60):after { - content: "color('red', 100)|#040001"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(61) { - background-color: #ffd4a0; - color: #000; } - .style-tile--color:nth-of-type(61):after { - content: "color('orange', 10)|#ffd4a0"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(62) { - background-color: #ffa573; - color: #000; } - .style-tile--color:nth-of-type(62):after { - content: "color('orange', 20)|#ffa573"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(63) { - background-color: #ff7832; - color: #000; } - .style-tile--color:nth-of-type(63):after { - content: "color('orange', 30)|#ff7832"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(64) { - background-color: #ff5003; - color: #000; } - .style-tile--color:nth-of-type(64):after { - content: "color('orange', 40)|#ff5003"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(65) { - background-color: #d74108; - color: #fff; } - .style-tile--color:nth-of-type(65):after { - content: "color('orange', 50)|#d74108"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(66) { - background-color: #a53725; - color: #fff; } - .style-tile--color:nth-of-type(66):after { - content: "color('orange', 60)|#a53725"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(67) { - background-color: #872a0f; - color: #fff; } - .style-tile--color:nth-of-type(67):after { - content: "color('orange', 70)|#872a0f"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(68) { - background-color: #6d120f; - color: #fff; } - .style-tile--color:nth-of-type(68):after { - content: "color('orange', 80)|#6d120f"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(69) { - background-color: #43100b; - color: #fff; } - .style-tile--color:nth-of-type(69):after { - content: "color('orange', 90)|#43100b"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(70) { - background-color: #030100; - color: #fff; } - .style-tile--color:nth-of-type(70):after { - content: "color('orange', 100)|#030100"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(71) { - background-color: #fde876; - color: #000; } - .style-tile--color:nth-of-type(71):after { - content: "color('yellow', 10)|#fde876"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(72) { - background-color: #fdd600; - color: #fff; } - .style-tile--color:nth-of-type(72):after { - content: "color('yellow', 20)|#fdd600"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(73) { - background-color: #efc100; - color: #fff; } - .style-tile--color:nth-of-type(73):after { - content: "color('yellow', 30)|#efc100"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(74) { - background-color: #be9b00; - color: #fff; } - .style-tile--color:nth-of-type(74):after { - content: "color('yellow', 40)|#be9b00"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(75) { - background-color: #8c7300; - color: #fff; } - .style-tile--color:nth-of-type(75):after { - content: "color('yellow', 50)|#8c7300"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(76) { - background-color: #735f00; - color: #fff; } - .style-tile--color:nth-of-type(76):after { - content: "color('yellow', 60)|#735f00"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(77) { - background-color: #574a00; - color: #fff; } - .style-tile--color:nth-of-type(77):after { - content: "color('yellow', 70)|#574a00"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(78) { - background-color: #3c3200; - color: #fff; } - .style-tile--color:nth-of-type(78):after { - content: "color('yellow', 80)|#3c3200"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(79) { - background-color: #281e00; - color: #fff; } - .style-tile--color:nth-of-type(79):after { - content: "color('yellow', 90)|#281e00"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(80) { - background-color: #020100; - color: #fff; } - .style-tile--color:nth-of-type(80):after { - content: "color('yellow', 100)|#020100"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(81) { - background-color: #e0e0e0; - color: #000; } - .style-tile--color:nth-of-type(81):after { - content: "color('gray', 10)|#e0e0e0"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(82) { - background-color: #c7c7c7; - color: #000; } - .style-tile--color:nth-of-type(82):after { - content: "color('gray', 20)|#c7c7c7"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(83) { - background-color: #aeaeae; - color: #000; } - .style-tile--color:nth-of-type(83):after { - content: "color('gray', 30)|#aeaeae"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(84) { - background-color: #959595; - color: #000; } - .style-tile--color:nth-of-type(84):after { - content: "color('gray', 40)|#959595"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(85) { - background-color: #777677; - color: #fff; } - .style-tile--color:nth-of-type(85):after { - content: "color('gray', 50)|#777677"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(86) { - background-color: #5a5a5a; - color: #fff; } - .style-tile--color:nth-of-type(86):after { - content: "color('gray', 60)|#5a5a5a"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(87) { - background-color: #464646; - color: #fff; } - .style-tile--color:nth-of-type(87):after { - content: "color('gray', 70)|#464646"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(88) { - background-color: #323232; - color: #fff; } - .style-tile--color:nth-of-type(88):after { - content: "color('gray', 80)|#323232"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(89) { - background-color: #121212; - color: #fff; } - .style-tile--color:nth-of-type(89):after { - content: "color('gray', 90)|#121212"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(90) { - background-color: #000; - color: #fff; } - .style-tile--color:nth-of-type(90):after { - content: "color('gray', 100)|#000"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(91) { - background-color: #dfe9e9; - color: #000; } - .style-tile--color:nth-of-type(91):after { - content: "color('cool-gray', 10)|#dfe9e9"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(92) { - background-color: #c8d2d2; - color: #000; } - .style-tile--color:nth-of-type(92):after { - content: "color('cool-gray', 20)|#c8d2d2"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(93) { - background-color: #aeb8b8; - color: #000; } - .style-tile--color:nth-of-type(93):after { - content: "color('cool-gray', 30)|#aeb8b8"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(94) { - background-color: #959f9f; - color: #000; } - .style-tile--color:nth-of-type(94):after { - content: "color('cool-gray', 40)|#959f9f"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(95) { - background-color: #6d7777; - color: #fff; } - .style-tile--color:nth-of-type(95):after { - content: "color('cool-gray', 50)|#6d7777"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(96) { - background-color: #586262; - color: #fff; } - .style-tile--color:nth-of-type(96):after { - content: "color('cool-gray', 60)|#586262"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(97) { - background-color: #3c4646; - color: #fff; } - .style-tile--color:nth-of-type(97):after { - content: "color('cool-gray', 70)|#3c4646"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(98) { - background-color: #323c3c; - color: #fff; } - .style-tile--color:nth-of-type(98):after { - content: "color('cool-gray', 80)|#323c3c"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(99) { - background-color: #0d1111; - color: #fff; } - .style-tile--color:nth-of-type(99):after { - content: "color('cool-gray', 90)|#0d1111"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(100) { - background-color: #000203; - color: #fff; } - .style-tile--color:nth-of-type(100):after { - content: "color('cool-gray', 100)|#000203"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(101) { - background-color: #e9e0e0; - color: #000; } - .style-tile--color:nth-of-type(101):after { - content: "color('warm-gray', 10)|#e9e0e0"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(102) { - background-color: #d0c7c7; - color: #000; } - .style-tile--color:nth-of-type(102):after { - content: "color('warm-gray', 20)|#d0c7c7"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(103) { - background-color: #b8aeae; - color: #000; } - .style-tile--color:nth-of-type(103):after { - content: "color('warm-gray', 30)|#b8aeae"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(104) { - background-color: #9e9494; - color: #000; } - .style-tile--color:nth-of-type(104):after { - content: "color('warm-gray', 40)|#9e9494"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(105) { - background-color: #7d7373; - color: #fff; } - .style-tile--color:nth-of-type(105):after { - content: "color('warm-gray', 50)|#7d7373"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(106) { - background-color: #645a5a; - color: #fff; } - .style-tile--color:nth-of-type(106):after { - content: "color('warm-gray', 60)|#645a5a"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(107) { - background-color: #504646; - color: #fff; } - .style-tile--color:nth-of-type(107):after { - content: "color('warm-gray', 70)|#504646"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(108) { - background-color: #3c3232; - color: #fff; } - .style-tile--color:nth-of-type(108):after { - content: "color('warm-gray', 80)|#3c3232"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(109) { - background-color: #1a1314; - color: #fff; } - .style-tile--color:nth-of-type(109):after { - content: "color('warm-gray', 90)|#1a1314"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(110) { - background-color: #030000; - color: #fff; } - .style-tile--color:nth-of-type(110):after { - content: "color('warm-gray', 100)|#030000"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(111) { - background-color: #fdfdfd; - color: #000; } - .style-tile--color:nth-of-type(111):after { - content: "color('neutral-white', 10)|#fdfdfd"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(112) { - background-color: #f9f9f9; - color: #000; } - .style-tile--color:nth-of-type(112):after { - content: "color('neutral-white', 20)|#f9f9f9"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(113) { - background-color: #f4f4f4; - color: #000; } - .style-tile--color:nth-of-type(113):after { - content: "color('neutral-white', 30)|#f4f4f4"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(114) { - background-color: #ececec; - color: #000; } - .style-tile--color:nth-of-type(114):after { - content: "color('neutral-white', 40)|#ececec"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(115) { - background-color: #fbfcfc; - color: #000; } - .style-tile--color:nth-of-type(115):after { - content: "color('cool-white', 10)|#fbfcfc"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(116) { - background-color: #f9f9fb; - color: #000; } - .style-tile--color:nth-of-type(116):after { - content: "color('cool-white', 20)|#f9f9fb"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(117) { - background-color: #f0f2f4; - color: #000; } - .style-tile--color:nth-of-type(117):after { - content: "color('cool-white', 30)|#f0f2f4"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(118) { - background-color: #ecf2f2; - color: #000; } - .style-tile--color:nth-of-type(118):after { - content: "color('cool-white', 40)|#ecf2f2"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(119) { - background-color: #fdfbfb; - color: #000; } - .style-tile--color:nth-of-type(119):after { - content: "color('warm-white', 10)|#fdfbfb"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(120) { - background-color: #fdfbfb; - color: #000; } - .style-tile--color:nth-of-type(120):after { - content: "color('warm-white', 20)|#fdfbfb"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(121) { - background-color: #f7f5f5; - color: #000; } - .style-tile--color:nth-of-type(121):after { - content: "color('warm-white', 30)|#f7f5f5"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(122) { - background-color: #f2eeee; - color: #000; } - .style-tile--color:nth-of-type(122):after { - content: "color('warm-white', 40)|#f2eeee"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(123) { - background-color: #fff; - color: #000; } - .style-tile--color:nth-of-type(123):after { - content: "color('grayscale', 10)|#fff"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(124) { - background-color: #fdfdfd; - color: #000; } - .style-tile--color:nth-of-type(124):after { - content: "color('grayscale', 20)|#fdfdfd"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(125) { - background-color: #f4f4f4; - color: #000; } - .style-tile--color:nth-of-type(125):after { - content: "color('grayscale', 30)|#f4f4f4"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(126) { - background-color: #ececec; - color: #000; } - .style-tile--color:nth-of-type(126):after { - content: "color('grayscale', 40)|#ececec"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(127) { - background-color: #e0e0e0; - color: #000; } - .style-tile--color:nth-of-type(127):after { - content: "color('grayscale', 50)|#e0e0e0"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(128) { - background-color: #aeaeae; - color: #000; } - .style-tile--color:nth-of-type(128):after { - content: "color('grayscale', 60)|#aeaeae"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(129) { - background-color: #777677; - color: #fff; } - .style-tile--color:nth-of-type(129):after { - content: "color('grayscale', 70)|#777677"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(130) { - background-color: #5a5a5a; - color: #fff; } - .style-tile--color:nth-of-type(130):after { - content: "color('grayscale', 80)|#5a5a5a"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(131) { - background-color: #323232; - color: #fff; } - .style-tile--color:nth-of-type(131):after { - content: "color('grayscale', 90)|#323232"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - .style-tile--color:nth-of-type(132) { - background-color: #121212; - color: #fff; } - .style-tile--color:nth-of-type(132):after { - content: "color('grayscale', 100)|#121212"; - visibility: hidden; - height: 0px; - width: 0px; - overflow: auto; - position: absolute; - top: 0rem; - left: 0rem; } - .style-tile--color-details { - color: inherit; } - -.style-tile--breakpoint:nth-of-type(1):after { - content: "setting-get('heading nav inline breakpoint') 700px"; - display: none; } - -.style-tile--breakpoint:nth-of-type(2):after { - content: "setting-get('tablet portrait') 768px"; - display: none; } - @media (min-width: 768px) { ._demo--container { width: 760px; diff --git a/public/images/samples/1.jpg b/public/images/samples/1.jpg old mode 100755 new mode 100644 index feae79f3..7bf67b98 Binary files a/public/images/samples/1.jpg and b/public/images/samples/1.jpg differ diff --git a/public/images/samples/3.jpg b/public/images/samples/3.jpg old mode 100755 new mode 100644 index 62d7e459..fe98fafc Binary files a/public/images/samples/3.jpg and b/public/images/samples/3.jpg differ diff --git a/public/js/demo.js b/public/js/demo.js index b75d08d5..9e72807e 100755 --- a/public/js/demo.js +++ b/public/js/demo.js @@ -14,7 +14,7 @@ * limitations under the License. */ - /* global $:false */ + /* global $:false, setupUse */ 'use strict'; // if image is landscape, tag it @@ -49,6 +49,54 @@ function imageFadeIn(imgSelector) { }); } +/** + * scroll animation to element on page + * @param {$element} Jquery element + * @return {void} + */ +function scrollToElement(element) { + $('html, body').animate({ + scrollTop: element.offset().top + }, 300); +} + +/** + * Returns the current page + * @return {String} the current page: test, train or use + */ +function currentPage() { + var href = $(window.location).attr('href'); + return href.substr(href.lastIndexOf('/')); +} + +/** + * Returns the next hour as Date + * @return {Date} the next hour + */ +function nextHour() { + var oneHour = new Date(); + oneHour.setHours(oneHour.getHours() + 1); + return oneHour; +} + +/** + * Resizes an image + * @param {String} image The base64 image + * @param {int} maxSize maximum size + * @return {String} The base64 resized image + */ +function resize(image, maxSize) { + var c = window.document.createElement('canvas'), + ctx = c.getContext('2d'), + ratio = image.width / image.height; + + c.width = (ratio > 1 ? maxSize : maxSize * ratio); + c.height = (ratio > 1 ? maxSize / ratio : maxSize); + + ctx.drawImage(image, 0, 0, c.width, c.height); + return c.toDataURL('image/jpeg'); +} + $(document).ready(function () { // tagging which images are landscape @@ -63,27 +111,12 @@ $(document).ready(function () { $(window).resize(square); - // tab listener + //tab listener $('.tab-panels--tab').click(function(e){ e.preventDefault(); var self = $(this); - var inputGroup = self.closest('.tab-panels'); - var idName = null; - - if (!self.hasClass('disabled')) { - inputGroup.find('.active').removeClass('active'); - self.addClass('active'); - idName = self.attr('href'); - $(idName).addClass('active'); - } - - square(); - landscapify('.use--example-image'); - landscapify('.use--output-image'); - landscapify('.train--bundle-thumb'); - landscapify('.test--example-image'); - landscapify('.test--output-image'); - - $('.dragover').removeClass('dragover'); + var newPanel = self.attr('href'); + if (newPanel !== currentPage()) + window.location = newPanel; }); }); diff --git a/public/js/train.js b/public/js/train.js index 92b6afca..4f5a9c03 100755 --- a/public/js/train.js +++ b/public/js/train.js @@ -14,8 +14,8 @@ * limitations under the License. */ - /* global $:false, _, trainPreviewImagesTemplate, testClassifierImagesTemplate, - landscapify, square, imageFadeIn, CLASSIFIER_ID */ + /* global $:false, Cookies, _, trainPreviewImagesTemplate, testClassifierImagesTemplate, + landscapify, square, imageFadeIn, CLASSIFIER_ID, setupUse, currentPage, nextHour*/ 'use strict'; @@ -176,58 +176,6 @@ return Math.round(num / 50 * 100) <= 100 ? Math.round(num / 50 * 100) : 100; } - /** - * Select the test page and configure it with the created classifier - * @param {Object} classifier The created classifier - */ - function setupTestPanel(classifier) { - CLASSIFIER_ID = classifier.classifier_id; - $('.tab-panels--tab[href="#panel2"]').trigger('click'); - scrollToElement($('.tab-views')); - $('.test--classifier-name').text(classifier.name); - landscapify('.test--example-image-overlay'); - imageFadeIn('.test--example-image-overlay'); - - function toggleSection(selector) { - $(selector).toggleClass('toggled'); - square(); - } - - // unbind all click events - $('.test--classifier-images-title').off('click'); - $('.test--classifier-images-toggle .test--classifier-images-arrow').off('click'); - $('.test--classifier-images-header').off('click'); - $('.test--header').off('click'); - $('.test--input-container .test--classifier-images-arrow').off('click'); - - // reset results - $('.test--output').hide(); - - $('.test--classifier-images-title').click(function(e) { - toggleSection('.test--classifier-images-toggle'); - landscapify('.test--classifier-images-image'); - }); - $('.test--classifier-images-toggle .test--classifier-images-arrow').click(function() { - toggleSection('.test--classifier-images-toggle'); - landscapify('.test--classifier-images-image'); - }); - $('.test--classifier-images-header').click(function() { - toggleSection('.test--classifier-images-toggle'); - landscapify('.test--classifier-images-image'); - }); - - $('.test--header').click(function(e) { - toggleSection('.test--input-container'); - landscapify('.test--example-image'); - landscapify('.test--output-image'); - }); - $('.test--input-container .test--classifier-images-arrow').click(function() { - toggleSection('.test--input-container'); - landscapify('.test--example-image'); - landscapify('.test--output-image'); - }); - } - /** * scroll animation to element on page * @param {$element} Jquery element @@ -249,27 +197,27 @@ */ $('.train--bundle-select-all').click(function() { var id = $(this).data('id'); - showTestSamples(id); + Cookies.set('bundle', id, { expires: nextHour()}); scrollToElement($('.tab-panels--tab-content')); - var dataset = datasets.filter(function(item) { return item.id === id; })[0]; - var positive = []; - var negative = []; - for (var i = 0; i < dataset.positive; i++) { - positive.push('images/datasets/' + id + '/positive/' + i + '.jpg'); - } - for (var j = 0; j < dataset.negative; j++) { - negative.push('images/datasets/' + id + '/negative/' + j + '.jpg'); - } + var dataset = datasets.filter(function(item) { return item.id === id; })[0]; + var positive = []; + var negative = []; + for (var i = 0; i < dataset.positive; i++) { + positive.push('images/datasets/' + id + '/positive/' + i + '.jpg'); + } + for (var j = 0; j < dataset.negative; j++) { + negative.push('images/datasets/' + id + '/negative/' + j + '.jpg'); + } - $error.hide(); - resetPreviews(); - loadPreviews(positive, negative); - $trainUrlInput.val(dataset.name); - showPreviews(); - setTrainButtonState(); - setInputErrorState(); - $('.tab-panels--tab[href="#panel3"]').addClass('disabled'); + $error.hide(); + resetPreviews(); + loadPreviews(positive, negative); + $trainUrlInput.val(dataset.name); + showPreviews(); + setTrainButtonState(); + setInputErrorState(); + $('.tab-panels--tab[href="/test"]').addClass('disabled'); }); $positiveClearButton.click(function(e) { @@ -305,7 +253,8 @@ $loading.show(); $error.hide(); - populateTestThumbnails(images.positives, images.negatives); + localStorage.setItem('positives', JSON.stringify(images.positives)); + localStorage.setItem('negatives', JSON.stringify(images.negatives)); xhr = $.ajax({ type: 'POST', @@ -315,8 +264,8 @@ dataType: 'json', success: function(result) { resetPage(); - setupTestPanel(result); - $('.tab-panels--tab[href="#panel3"]').removeClass('disabled').trigger('click'); + Cookies.set('classifier', result, { expires: nextHour()}); + $('.tab-panels--tab[href="/test"]').trigger('click'); }, error: function(err) { $loading.hide(); @@ -334,7 +283,7 @@ $trainUrlInput.on('propertychange change click keyup input paste', function() { setTrainButtonState(); setInputErrorState(); - $('.tab-panels--tab[href="#panel3"]').addClass('disabled'); + $('.tab-panels--tab[href="/test"]').addClass('disabled'); }); function populateTestThumbnails(positives, negatives) { @@ -397,7 +346,7 @@ } $('.train--dropzone label').removeClass('dragover'); resetTestSamples(); - $('.tab-panels--tab[href="#panel3"]').addClass('disabled'); + $('.tab-panels--tab[href="/test"]').addClass('disabled'); }, error: _error, done: function(e, data) { @@ -416,19 +365,6 @@ $('.train--dropzone label').removeClass('dragover'); }); - - function resize(image, maxSize) { - var c = window.document.createElement('canvas'), - ctx = c.getContext('2d'), - ratio = image.width / image.height; - - c.width = (ratio > 1 ? maxSize : maxSize * ratio); - c.height = (ratio > 1 ? maxSize / ratio : maxSize); - - ctx.drawImage(image, 0, 0, c.width, c.height); - return c.toDataURL('image/jpeg'); - } - function setTrainButtonState() { var button = document.querySelector('.train--train-button'); if ($trainUrlInput.val() !== '' && @@ -465,12 +401,80 @@ $('.test--example-images_default').show(); } - $('.tab-panels--tab[href="#panel2"]').click(function() { - if (xhr) - xhr.abort(); - setTrainButtonState(); - setInputErrorState(); - resetPage(); - }); + // init pages + setupUse({ panel: 'use'}); + setupUse({ panel: 'test', useClassifierId: true}); + + /** + * Select the test page and configure it with the created classifier + * @param {Object} classifier The created classifier + */ + function setupTestPanel(classifier) { + CLASSIFIER_ID = classifier.classifier_id; + $('.test--classifier-name').text(classifier.name); + landscapify('.test--example-image-overlay'); + imageFadeIn('.test--example-image-overlay'); + + function toggleSection(selector) { + $(selector).toggleClass('toggled'); + square(); + } + + // unbind all click events + $('.test--classifier-images-title').off('click'); + $('.test--classifier-images-toggle .test--classifier-images-arrow').off('click'); + $('.test--classifier-images-header').off('click'); + $('.test--header').off('click'); + $('.test--input-container .test--classifier-images-arrow').off('click'); + + // reset results + $('.test--output').hide(); + $('.test--classifier-images-title').click(function() { + toggleSection('.test--classifier-images-toggle'); + landscapify('.test--classifier-images-image'); + }); + $('.test--classifier-images-toggle .test--classifier-images-arrow').click(function() { + toggleSection('.test--classifier-images-toggle'); + landscapify('.test--classifier-images-image'); + }); + $('.test--classifier-images-header').click(function() { + toggleSection('.test--classifier-images-toggle'); + landscapify('.test--classifier-images-image'); + }); + + $('.test--header').click(function() { + toggleSection('.test--input-container'); + landscapify('.test--example-image'); + landscapify('.test--output-image'); + }); + $('.test--input-container .test--classifier-images-arrow').click(function() { + toggleSection('.test--input-container'); + landscapify('.test--example-image'); + landscapify('.test--output-image'); + }); + } + + + var classifier = Cookies.get('classifier'); + // enable test if there is trained classifier + if (classifier) + $('.tab-panels--tab[href="/test"]').removeClass('disabled'); + + // send the user to train if they hit /test without a trained classifier + if (currentPage() === '/test') { + if (classifier){ + showTestSamples(Cookies.get('bundle') || 'default'); + populateTestThumbnails(JSON.parse(localStorage['positives'] || '[]'), JSON.parse(localStorage['negatives'] || '[]')); + if (!localStorage['positives'] || !localStorage['negatives']) + $('.test--classifier-images-container').hide(); + else + $('.test--classifier-images-container').show(); + square(); + $(window).resize(square); + setupTestPanel(JSON.parse(Cookies.get('classifier') || '{}')); + } else { + $('.tab-panels--tab[href="/train"]').trigger('click'); + } + } }); diff --git a/public/js/use.js b/public/js/use.js index 1e387f0c..2bb821da 100755 --- a/public/js/use.js +++ b/public/js/use.js @@ -16,7 +16,7 @@ 'use strict'; var CLASSIFIER_ID = null; -/*global $:false */ +/*global $:false, resize */ /** * Setups the "Try Out" and "Test" panels. @@ -45,10 +45,10 @@ function setupUse(params) { $tbody = $(pclass + 'output-tbody'), $image = $(pclass + 'output-image'), $urlInput = $(pclass + 'url-input'), + $imageDataInput = $(pclass + 'image-data-input'), $radioImages = $(pclass + 'example-radio'), $invalidImageUrl = $(pclass + 'invalid-image-url').hide(), $invalidUrl = $(pclass + 'invalid-url').show(), - $trainButton = $(pclass + 'train-button'), $dropzone = $(pclass + 'dropzone'), $fileupload = $(pid + 'fileupload'); @@ -90,8 +90,9 @@ function setupUse(params) { if (!scores || scores.length === 0) { var message = 'The image could not be classified'; - if ($('#panel3').hasClass('active')) - message = 'Not a positive match for ' + $('.test--classifier-name').text() + ' with a confidence above 50%'; + if ($('#test').hasClass('active')) + message = 'Not a positive match for ' + $('.test--classifier-name').text() + + ' with a confidence above 50%'; $tbody.html( '' + '' + @@ -148,10 +149,12 @@ function setupUse(params) { /* * submit event */ - function classifyImage(imgPath) { + function classifyImage(imgPath, imageData) { processImage(); - $image.attr('src', imgPath); + if (imgPath !== '') + $image.attr('src', imgPath); $urlInput.val(imgPath); + $imageDataInput.val(imageData); var url = '/api/classify'; if (useClassifierId === true && CLASSIFIER_ID) @@ -160,10 +163,10 @@ function setupUse(params) { // Grab all form data $.post(url, $(pclass + 'form').serialize()) .done(showResult) - .error(function(err) { + .error(function() { $loading.hide(); - // showError(err.responseJSON.error); - showError('The demo is not available right now.
We are working on getting this back up and running soon.'); + showError('The demo is not available right now.
We are working on ' + + 'getting this back up and running soon.'); }); } @@ -205,7 +208,7 @@ function setupUse(params) { self.addClass(panel + '--url-input_error'); } else { resetPasteUrl(); - classifyImage(url); + convertFileToDataURLviaFileReader(url, classifyImage.bind(classifyImage, url)); self.blur(); } }); @@ -215,14 +218,6 @@ function setupUse(params) { $(self).focus(); }); - /* - * Image url submission - */ - $trainButton.click(function() { - $('.tab-panels--tab[href="#panel2"]').trigger('click'); - scrollToElement($('.tab-views')); - }); - function resetPasteUrl() { $urlInput.removeClass(panel + '--url-input_error'); $invalidUrl.hide(); @@ -239,14 +234,9 @@ function setupUse(params) { add: function(e, data) { var path = (useClassifierId && CLASSIFIER_ID) ? '?classifier_id=' + CLASSIFIER_ID : ''; data.url = '/api/classify' + path; - console.log($fileupload); if (data.files && data.files[0]) { - if(data.files[0]['size'] > 5242880) { - showError('The file size exceeds the limit allowed. The maximum file size is 5 MB.'); - return; - } else { - $error.hide(); - } + $error.hide(); + processImage(); var reader = new FileReader(); reader.onload = function() { @@ -254,10 +244,12 @@ function setupUse(params) { image.src = reader.result; image.onload = function() { $image.attr('src', this.src); + classifyImage('', resize(image, 640)); }; }; reader.readAsDataURL(data.files[0]); - data.submit(); + // do not submit the image + //data.submit(); } }, error: _error, @@ -308,6 +300,23 @@ function setupUse(params) { $(pclass + 'dropzone label').removeClass('dragover'); }); + function convertFileToDataURLviaFileReader(url, callback){ + var xhr = new XMLHttpRequest(); + xhr.responseType = 'blob'; + xhr.onload = function() { + var reader = new FileReader(); + reader.onloadend = function () { + var image = new Image(); + image.src = reader.result; + image.onload = function() { + callback(resize(image, 640)); + }; + }; + reader.readAsDataURL(xhr.response); + }; + xhr.open('GET', url); + xhr.send(); + } /** * scroll animation to element on page * @param {$element} Jquery element @@ -319,9 +328,3 @@ function setupUse(params) { }, 300); } } - -// init pages -$(function() { - setupUse({ panel: 'use'}); - setupUse({ panel: 'test', useClassifierId: true}); -}); diff --git a/views/includes/test.jade b/views/includes/test.jade index 68424e27..e9a00645 100644 --- a/views/includes/test.jade +++ b/views/includes/test.jade @@ -7,17 +7,18 @@ hr.base--hr.test--hr i.test--classifier-images-arrow.icon.icon-down-arrow +sampleInput('test') hr.base--hr.test--hr -.test--classifier-images-toggle - h3.test--classifier-images-title.base--h3 Show your trained images - i.test--classifier-images-arrow.icon.icon-down-arrow - .test--classifier-images - .test--classifier-images-left - h3.base--h3.test--classifier-images-header Positive Images - .test--classifier-images-thumbs.test--classifier-images-thumbs_positive - .test--classifier-images-right - h3.base--h3.test--classifier-images-header Negative Images - .test--classifier-images-thumbs.test--classifier-images-thumbs_negative -hr.base--hr.test--hr +.test--classifier-images-container + .test--classifier-images-toggle + h3.test--classifier-images-title.base--h3 Show your trained images + i.test--classifier-images-arrow.icon.icon-down-arrow + .test--classifier-images + .test--classifier-images-left + h3.base--h3.test--classifier-images-header Positive Images + .test--classifier-images-thumbs.test--classifier-images-thumbs_positive + .test--classifier-images-right + h3.base--h3.test--classifier-images-header Negative Images + .test--classifier-images-thumbs.test--classifier-images-thumbs_negative + hr.base--hr.test--hr .loading.test--loading img.test--loading-image.loading--image(src='images/loading-indicator.gif') p.base--p.test--loading-message.loading--message Visual Recognition is classifying the image to determine a match... diff --git a/views/includes/use.jade b/views/includes/use.jade index aea90011..eb5816a8 100644 --- a/views/includes/use.jade +++ b/views/includes/use.jade @@ -24,7 +24,9 @@ h2.base--h2.use--header Select an Image td.base--td.use--output-td a.base--a(href='https://www.ibm.com/smarterplanet/us/en/ibmwatson/developercloud/doc/visual-recognition/overview.shtml', target='_blank') Confidence Score tbody.use--output-tbody - .use--output-note You can use your own images to create a custom classifier that is tailored to your needs. + .use--output-note Powered by + a.base--a(href='http://www.alchemyapi.com/products/alchemyvision', target='_blank') AlchemyVision hr.base--hr.use--hr .use--output-row - button.base--button.use--train-button Create a custom classifier + a(href='/train') + button.base--button.use--train-button Create a custom classifier diff --git a/views/index.jade b/views/index.jade deleted file mode 100755 index d895fe93..00000000 --- a/views/index.jade +++ /dev/null @@ -1,20 +0,0 @@ -extends ./layout.jade - -block content - ._demo--container - article._content.base--article - .tab-panels.tab-views(role='tabpanel') - ul.tab-panels--tab-list.tab-views--tab-list(role='tablist') - li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') - a.tab-panels--tab.tab-views--tab.active(href='#panel1', aria-controls='panel1', role='tab') Try out - li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') - a.tab-panels--tab.tab-views--tab(href='#panel2', aria-controls='panel2', role='tab') Train - li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') - a.tab-panels--tab.tab-views--tab.disabled(href='#panel3', aria-controls='panel3', role='tab') Test - .tab-panels--tab-content - #panel1.tab-views--tab-pane.tab-panels--tab-pane.active(role='tab-panel') - include ./includes/use.jade - #panel2.tab-views--tab-pane.tab-panels--tab-pane(role='tab-panel') - include ./includes/train.jade - #panel3.tab-views--tab-pane.tab-panels--tab-pane(role='tab-panel') - include ./includes/test.jade diff --git a/views/layout.jade b/views/layout.jade index a2e44ccb..25fe7a34 100755 --- a/views/layout.jade +++ b/views/layout.jade @@ -32,7 +32,7 @@ html(lang='en') img.banner--service-icon_INLINE(src='images/service-icon.svg', alt='Visual Recognition API Icon') | Visual Recognition .banner--service-description - | Visual Recognition allows you to derive insights from an image based on its visual content. You can organize image libraries, understand an individual image, and create custom classifiers for specific results that are tailored to your needs. + | Visual Recognition partnered with Alchemy Vision, allows you to derive insights from an image based on its visual content. You can organize image libraries, understand an individual image, and create custom classifiers for specific results that are tailored to your needs. .banner--service-resource span.icon.icon-link strong Resources: @@ -45,17 +45,18 @@ html(lang='en') a.base--a(href='https://github.com/watson-developer-cloud/visual-recognition-nodejs') Fork on Github li.base--li.banner--service-link-item a.base--a(href='https://bluemix.net/deploy?repository=https://github.com/watson-developer-cloud/visual-recognition-nodejs') Fork and Deploy on Bluemix - - block content + ._demo--container + article._content.base--article + block content include ./includes/underscore-templates.jade script(src='https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js') script(src='https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js') script(src='https://cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.5.7/jquery.fileupload.min.js') script(src='https://cdnjs.cloudflare.com/ajax/libs/blueimp-file-upload/9.5.7/jquery.iframe-transport.min.js') script(src='https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js') + script(src='https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.1.0/js.cookie.min.js') + script(src='js/demo.js') script(src='js/use.js') script(src='js/train.js') - script(src='js/demo.js') script(src='js/vendors/tealeaf.js') script(src='js/vendors/ga.js') - block extra-scripts diff --git a/views/mixins/sampleInput.jade b/views/mixins/sampleInput.jade index d7be07b7..3c72e64a 100644 --- a/views/mixins/sampleInput.jade +++ b/views/mixins/sampleInput.jade @@ -17,9 +17,11 @@ mixin sampleInput(className) form(id='#{className}--fileupload', class='#{className}--form', data-upload-template-id='template-upload-#{className}') div(class='#{className}--example-images #{className}--example-images_default') +sampleImages(sampleImages, className, 'default') - each dataset, index in datasets - div(class='#{className}--example-images #{className}--example-images_#{dataset.id}') - +sampleImages(images[index], className, dataset.id) + if className != 'use' + each dataset, index in datasets + div(class='#{className}--example-images #{className}--example-images_#{dataset.id}') + +sampleImages(images[index], className, dataset.id) + div(class='#{className}--dropzone') label(class='#{className}--file-input-button base--button', for='#{className}--file') span.base--a Select an image @@ -29,3 +31,4 @@ mixin sampleInput(className) div(class='#{className}--invalid-url') Invalid URL div(class='#{className}--invalid-image-url') The URL must end with .JPG, .GIF, or .PNG. input(class='#{className}--url-input base--input', type='text', placeholder='Paste image URL here', name='url') + input(class='#{className}--image-data-input base--input', type='hidden', name='image_data') diff --git a/views/test.jade b/views/test.jade new file mode 100644 index 00000000..0c6bf539 --- /dev/null +++ b/views/test.jade @@ -0,0 +1,13 @@ +extends ./layout.jade + +block content + .tab-panels.tab-views(role='tabpanel') + ul.tab-panels--tab-list.tab-views--tab-list(role='tablist') + li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') + a.tab-panels--tab.tab-views--tab(href='/', aria-controls='panel1', role='tab') Try out + li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') + a.tab-panels--tab.tab-views--tab(href='/train', aria-controls='panel2', role='tab') Train + li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') + a.tab-panels--tab.tab-views--tab.active(href='/test', aria-controls='panel3', role='tab') Test + .tab-panels--tab-content + include ./includes/test.jade diff --git a/views/train.jade b/views/train.jade new file mode 100644 index 00000000..ffd300cc --- /dev/null +++ b/views/train.jade @@ -0,0 +1,13 @@ +extends ./layout.jade + +block content + .tab-panels.tab-views(role='tabpanel') + ul.tab-panels--tab-list.tab-views--tab-list(role='tablist') + li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') + a.tab-panels--tab.tab-views--tab(href='/', aria-controls='panel1', role='tab') Try out + li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') + a.tab-panels--tab.tab-views--tab.active(href='/train', aria-controls='panel2', role='tab') Train + li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') + a.tab-panels--tab.tab-views--tab.disabled(href='/test', aria-controls='panel3', role='tab') Test + .tab-panels--tab-content + include ./includes/train.jade diff --git a/views/use.jade b/views/use.jade new file mode 100644 index 00000000..2be4153c --- /dev/null +++ b/views/use.jade @@ -0,0 +1,13 @@ +extends ./layout.jade + +block content + .tab-panels.tab-views(role='tabpanel') + ul.tab-panels--tab-list.tab-views--tab-list(role='tablist') + li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') + a.tab-panels--tab.tab-views--tab.active(href='/', aria-controls='panel1', role='tab') Try out + li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') + a.tab-panels--tab.tab-views--tab(href='/train', aria-controls='panel2', role='tab') Train + li.tab-panels--tab-list-item.tab-views--tab-list-item.base--li(role='presentation') + a.tab-panels--tab.tab-views--tab.disabled(href='/test', aria-controls='panel3', role='tab') Test + .tab-panels--tab-content + include ./includes/use.jade