Appendix: Complete code for all projects

  1. Project 1. Does the photo contain a certain object?
  2. Project 2. Find a similar item in an online store
  3. Project 3. Does the item found look similar to the original?
  4. Project 4. Which of the found items is most similar to the original?

Project 1. Does the photo contain a certain object?

Specifications:

Input:
{
  "image": {
    "type": "url",
    "hidden": false,
    "required": true
  }
}
Output:
{
  "result": {
    "type": "string",
    "hidden": false,
    "required": true
  }
}

HTML:

{{img src=image width="100%" height="400px"}}
<div>Are there <b>shoes</b> in the picture?<div>
<div> {{field type="radio" name="result" value="OK" label="Yes" hotkey="1"}}
{{field type="radio" name="result" value="BAD" label="No" hotkey="2"}}
{{field type="radio" name="result" value="404" label="Loading error" hotkey="3"}}</div>

JavaScript:

exports.Task = extend(TolokaHandlebarsTask, function(options) {
    TolokaHandlebarsTask.call(this, options);
}, {
    onRender: function() {
        // DOM element for task is formed (available via #getDOMElement()) 
    },
    onDestroy: function() {
        // Task is completed. Global resources can be released (if used)
    }
});

function extend(ParentClass, constructorFunction, prototypeHash) {
    constructorFunction = constructorFunction || function() {};
    prototypeHash = prototypeHash || {};
    if (ParentClass) {
        constructorFunction.prototype = Object.create(ParentClass.prototype);
    }
    for (var i in prototypeHash) {
        constructorFunction.prototype[i] = prototypeHash[i];
    }
    return constructorFunction;
}

Project 2. Find a similar item in an online store

Specifications:

Input:

{
  "image": {
    "type": "url",
    "hidden": false,
    "required": true
  }
}

Output:

{
  "button": {
    "type": "boolean",
    "hidden": false,
    "required": true,
    "allowed_values": [
      true
    ]
  },
  "found_link": {
    "type": "string",
    "hidden": false,
    "pattern": "https://www.asos.com/.*",
    "required": true
  },
  "found_image": {
    "type": "file",
    "hidden": false,
    "required": true
  }
}

HTML:

{{img src=image width="50%" height="400px"}}
<div class='answers'>
    <p>Find similar <b>shoes</b> in the ASOS online store</p>
 {{field type="button-clicked" name="button" label="ASOS" href="https://www.asos.com" action=true}}
    <p>Shoes must be similar in color, material, length, and style.</p>
 <p>Paste the link here</p> 
{{field width="100%" type="input" name="found_link"}}
    <p>Upload the image here</p>
    <div> 
{{field width="100%" type="file-img" name="found_image" preview=true}} 
</div>
</div>

JavaScript:

exports.Task = extend(TolokaHandlebarsTask, function(options) {
    TolokaHandlebarsTask.call(this, options);
}, {
    validate: function(solution) {

        if (!solution.output_values.found_image) {

            return {
                task_id: this.getTask().id,
                errors: {
                    '__TASK__': {
                        message: 'Upload photo or mark that there is no photo'
                    }
                }
            };
        } else {
            return TolokaHandlebarsTask.prototype.validate.apply(this, arguments);
        }
    },
    onRender: function() {
        // DOM element for task is formed (available via #getDOMElement()) 
    },
    onDestroy: function() {
        // Task is completed. Global resources can be released (if used)
    }
});

function extend(ParentClass, constructorFunction, prototypeHash) {
    constructorFunction = constructorFunction || function() {};
    prototypeHash = prototypeHash || {};
    if (ParentClass) {
        constructorFunction.prototype = Object.create(ParentClass.prototype);
    }
    for (var i in prototypeHash) {
        constructorFunction.prototype[i] = prototypeHash[i];
    }
    return constructorFunction;
}

CSS:

.task {
    display: block;
    height: 500px;
    width: 800px;
}

.img {
    float: left;
    width: 50%;
}

.answers {
    float: left;
    width: 40%;
    margin: 5%;
}

Project 3. Does the item found look similar to the original?

Specifications:

Input:

{
  "image": {
    "type": "url",
    "hidden": false,
    "required": true
  },
  "found_link": {
    "type": "url",
    "hidden": false,
    "required": true
  },
  "assignment_id": {
    "type": "string",
    "hidden": true,
    "required": true
  }
}

Output:

{
  "result": {
    "type": "string",
    "hidden": false,
    "required": true
  }
}

HTML:

{{img src=image height="400px"}} {{iframe src= found_link height="600px"}}
<p>Make sure that the uploaded image matches the product from the store.</p> 
{{button label="Check the product" href=found_link action=true}}
<p>Are these <b>shoes</b> similar?</p>
<p>Shoes must be the same color, fabric, length, and style.</p> 
{{field type="radio" name="result" value="Yes" label="Yes"}} 
{{field type="radio" name="result" value="No" label="No"}}

JavaScript:

exports.Task = extend(TolokaHandlebarsTask, function(options) {
    TolokaHandlebarsTask.call(this, options);
}, {
    onRender: function() {
        // DOM element for task is formed (available via #getDOMElement()) 
    },
    onDestroy: function() {
        // Task is completed. Global resources can be released (if used)
    }
});

function extend(ParentClass, constructorFunction, prototypeHash) {
    constructorFunction = constructorFunction || function() {};
    prototypeHash = prototypeHash || {};
    if (ParentClass) {
        constructorFunction.prototype = Object.create(ParentClass.prototype);
    }
    for (var i in prototypeHash) {
        constructorFunction.prototype[i] = prototypeHash[i];
    }
    return constructorFunction;
}
CSS:
.task {
    display: block;
}

.img {
    float: left;
    width: 50%;
}

.iframe {
    float: left;
    width: 50%;
}

Project 4. Which of the found items is most similar to the original?

Specifications:

Input:

{
  "image": {
    "type": "url",
    "hidden": false,
    "required": true
  },
  "left_link": {
    "type": "url",
    "hidden": false,
    "required": true
  },
  "right_link": {
    "type": "url",
    "hidden": false,
    "required": true
  }
}

Output:

{
  "result": {
    "type": "url",
    "hidden": false,
    "required": true
  }
}

HTML:

<div class="header">
    <div class="left caption"> {{button label="Go to site" href=left_link size="L"}}
        <p class="url">{{left_link}}</p>
    </div>
    <div class="right caption">
        <p class="url">{{right_link}}</p>
        {{button label="Go to site" href=right_link size="L"}}
    </div>
</div> {{img src=image}}
<div class="content clearfix">
    <div class="left page">
        {{iframe src=uploaded_link_left width="100%" height="700px" real-size=true screenshot=true}}
    </div>
    <div class="right page">
        {{iframe src=uploaded_link_right width="100%" height="700px" real-size=true screenshot=true}}
    </div>
</div>
<div class="footer">
    {{field type="radio" name="result" label="Left image is better" value=result_left hotkey="1"}}
    {{field type="radio" name="result" label="Right image is better" value=result_right hotkey="2"}}
</div>

JavaScript:

exports.Task = extend(TolokaHandlebarsTask, function(options) {
    TolokaHandlebarsTask.call(this, options);
}, {
    getTemplateData: function() {
        var data = TolokaHandlebarsTask.prototype.getTemplateData.apply(this, arguments),
            input = this.getTask().input_values;
        var left_link = input.left_link;
        var right_link = input.right_link;
        var uploaded_link_left = '',
            uploaded_link_right = ''
        if (Math.floor(Math.random() * 2)) {
            uploaded_link_left = left_link
            uploaded_link_right = right_link
        } else {
            uploaded_link_left = right_link
            uploaded_link_right = left_link
        }
        data.uploaded_link_left = uploaded_link_left;
        data.uploaded_link_right = uploaded_link_right;
        data.result_left = uploaded_link_left;
        data.result_right = uploaded_link_right;

        return data;

    },

    onRender: function() {
        // DOM element for task is formed (available via #getDOMElement()) 
    },
    onDestroy: function() {
        // Task is completed. Global resources can be released (if used)
    }
});

function extend(ParentClass, constructorFunction, prototypeHash) {
    constructorFunction = constructorFunction || function() {};
    prototypeHash = prototypeHash || {};
    if (ParentClass) {
        constructorFunction.prototype = Object.create(ParentClass.prototype);
    }
    for (var i in prototypeHash) {
        constructorFunction.prototype[i] = prototypeHash[i];
    }
    return constructorFunction;
}
CSS:
.task {
    display: block;
    text-align: center;
}

.header {
    overflow: hidden;
    background-color: #FFCC00;
}

.caption {
    width: 50%;
}

.url {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;

    max-width: calc(100% - 182px);

    display: inline-block;
    vertical-align: bottom;
}

.button {
    margin: 10px;
    max-width: 182px;
}


.content {
    margin: 10px 0;
}

.page {
    display: inline-block;
    width: 50%;
}

.left {
    float: left;
    text-align: left;
}

.right {
    float: right;
    text-align: right;
}

.clearfix {
    overflow: hidden;
    width: 100%;
}


.image {
    display: inline-block;
    width: 50%;
}.task {
    display: block;
    text-align: center;
}

.header {
    overflow: hidden;
    background-color: #FFCC00;
}

.caption {
    width: 50%;
}

.url {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;

    max-width: calc(100% - 182px);

    display: inline-block;
    vertical-align: bottom;
}

.button {
    margin: 10px;
    max-width: 182px;
}


.content {
    margin: 10px 0;
}

.page {
    display: inline-block;
    width: 50%;
}

.left {
    float: left;
    text-align: left;
}

.right {
    float: right;
    text-align: right;
}

.clearfix {
    overflow: hidden;
    width: 100%;
}

.image {
    display: inline-block;
    width: 50%;
}