text:
/*
 * Client memory data source for the table control.
 */
+function ($) { "use strict";

    // NAMESPACE CHECK
    // ============================

    if ($.oc.table === undefined)
        throw new Error("The $.oc.table namespace is not defined. Make sure that the table.js script is loaded.");

    if ($.oc.table.datasource === undefined)
        throw new Error("The $.oc.table.datasource namespace is not defined. Make sure that the table.datasource.base.js script is loaded.");

    // CLASS DEFINITION
    // ============================

    var Base = $.oc.table.datasource.base,
        BaseProto = Base.prototype

    var Client = function(tableObj) {
        Base.call(this, tableObj)

        var dataString = tableObj.getElement().getAttribute('data-data')

        if (dataString === null || dataString === undefined)
            throw new Error('The required data-data attribute is not found on the table control element.')

        this.data = JSON.parse(dataString)
    };

    Client.prototype = Object.create(BaseProto)
    Client.prototype.constructor = Client

    Client.prototype.dispose = function() {
        BaseProto.dispose.call(this)
        this.data = null
    }

    /*
     * Fetches records from the underlying data source and
     * passes them to the onSuccess callback function.
     * The onSuccess callback parameters: records, totalCount.
     * Each record contains the key field which uniquely identifies
     * the record. The name of the key field is defined with the table
     * widget options.
     */
    Client.prototype.getRecords = function(offset, count, onSuccess) {
        if (!count) {
            // Return all records
            onSuccess(this.data, this.data.length)
        } else {
            // Return a subset of records
            onSuccess(this.data.slice(offset, offset+count), this.data.length)
        }
    }

    /*
     * Creates a record with the passed data and returns the updated page records
     * to the onSuccess callback function.
     *
     * - recordData - the record fields
     * - placement - "bottom" (the end of the data set), "above", "below"
     * - relativeToKey - a row key, required if the placement is not "bottom"
     * - offset - the current page's first record index (zero-based)
     * - count - number of records to return
     * - onSuccess - a callback function to execute when the updated data gets available.
     *
     * The onSuccess callback parameters: records, totalCount.
     */
    Client.prototype.createRecord = function(recordData, placement, relativeToKey, offset, count, onSuccess) {
        if (placement === 'bottom') {
            // Add record to the bottom of the dataset
            this.data.push(recordData)
        }
        else if (placement == 'above' || placement == 'below') {
            // Add record above or below the passed record key
            var recordIndex = this.getIndexOfKey(relativeToKey)
            if (placement == 'below')
                recordIndex ++

            this.data.splice(recordIndex, 0, recordData)
        }

        this.getRecords(offset, count, onSuccess)
    }

    /*
     * Updates a record with the specified key with the passed data
     *
     * - key - the record key in the dataset (primary key, etc)
     * - recordData - the record fields.
     */
    Client.prototype.updateRecord = function(key, recordData) {
        var recordIndex = this.getIndexOfKey(key)

        if (recordIndex !== -1) {
            recordData[this.tableObj.options.keyColumn] = key
            this.data[recordIndex] = recordData
        }
        else {
            throw new Error('Record with they key '+key+ ' is not found in the data set')
        }
    }

    /*
     * Deletes a record with the specified key.
     *
     * - key - the record key in the dataset (primary key, etc).
     * - newRecordData - replacement record to add to the dataset if the deletion
     *   empties it.
     * - offset - the current page's first record key (zero-based)
     * - count - number of records to return
     * - onSuccess - a callback function to execute when the updated data gets available.
     *
     * The onSuccess callback parameters: records, totalCount.
     */
    Base.prototype.deleteRecord = function(key, newRecordData, offset, count, onSuccess) {
        var recordIndex = this.getIndexOfKey(key)

        if (recordIndex !== -1) {
            this.data.splice(recordIndex, 1)

            if (this.data.length == 0)
                this.data.push(newRecordData)

            this.getRecords(offset, count, onSuccess)
        }
        else {
            throw new Error('Record with they key '+key+ ' is not found in the data set')
        }
    }

    Client.prototype.getIndexOfKey = function(key) {
        var keyColumn = this.tableObj.options.keyColumn

        return this.data.map(function(record) {
            return record[keyColumn] + ""
        }).indexOf(key + "")
    }

    Client.prototype.getAllData = function() {
        return this.data
    }

    $.oc.table.datasource.client = Client
}(window.jQuery);


text:
package springWebGallery.db.jdbcDao;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import springWebGallery.db.dao.PhotoDAO;
import springWebGallery.models.Photo;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class JdbcPhotoDAO extends AbstractDAO implements PhotoDAO {

    private static String PHOTO_ID = "idPhoto";
    private static String USER_ID = "idUser";
    private static String PHOTO_DATA = "data";
    private static String PHOTO_DESCRIPTION = "description";

    private static String SELECT_PHOTOS_BY_USER_ID = "SELECT \"idPhoto\" FROM webimagegallery.gallery_photos " +
            "WHERE \"idUser\" = :idUser ORDER BY \"idPhoto\" DESC LIMIT :photosAmount OFFSET :page";

    private static String SELECT_PHOTO_BY_ID = "SELECT * FROM webimagegallery.gallery_photos WHERE \"idPhoto\" = :idPhoto";

    private static String INSERT_NEW_PHOTO = "INSERT INTO webimagegallery.gallery_photos (\"idUser\", data, description) " +
            "VALUES (:idUser, :data, :description)";

    private static String UPDATE_PHOTO_DESCRIPTION_BY_ID = "UPDATE webimagegallery.gallery_photos SET " +
            "description = :description " +
            "WHERE idPhoto = :idPhoto;";

    private static String DELETE_PHOTO_BY_ID = "DELETE FROM webimagegallery.gallery_photos WHERE \"idPhoto\" = :idPhoto";
    private static final String GET_LAST_USED_ID = "SELECT last_value FROM webimagegallery.\"gallery_photos_idPhoto_seq\"";

    private Connection connection = null;

    private DriverManagerDataSource dataSource;

    public void setDataSource(DriverManagerDataSource dataSource) {
        this.dataSource = dataSource;
    }

    public DriverManagerDataSource getDataSource() {
        return dataSource;
    }

    private MapSqlParameterSource fillMapSqlParametersSourceWithData(MapSqlParameterSource parameterMap, Photo photo) {
        parameterMap.addValue(USER_ID, photo.getIdUser());
        parameterMap.addValue(PHOTO_DATA, photo.getImageData());
        parameterMap.addValue(PHOTO_DESCRIPTION, photo.getImageDescription());
        return parameterMap;
    }

    @Override
    public ArrayList<Integer> findPhotosByUserId(int userId, int amountOfPhotos, int page) {
        if (userId != 0 && amountOfPhotos !=0) {
            connection = null;
            try {
                connection = dataSource.getConnection();
                NamedParameterJdbcTemplate namedSelect = new NamedParameterJdbcTemplate(this.dataSource);
                MapSqlParameterSource selectParameters = new MapSqlParameterSource();
                selectParameters.addValue("idUser", userId);
                selectParameters.addValue("photosAmount", amountOfPhotos);
                selectParameters.addValue("page", page);

                ArrayList<Integer> photos = (ArrayList<Integer>) namedSelect.queryForList(SELECT_PHOTOS_BY_USER_ID, selectParameters, Integer.class);

                connection.close();
                logger.info("Extracted photos for user with id " + userId + " , amount is " + amountOfPhotos + " , pagination " + page);
                return photos;

            } catch (SQLException e) {
                handleSqlException(e);
            } finally {
                closeConnection(connection);
            }
        }
        return null;
    }

    @Override
    public Photo findByPhotoId(int photoId) {
        if (photoId > 0) {
            connection = null;
            try {
                connection = dataSource.getConnection();
                NamedParameterJdbcTemplate namedSelect = new NamedParameterJdbcTemplate(this.dataSource);
                MapSqlParameterSource selectParameters = new MapSqlParameterSource();
                selectParameters.addValue("idPhoto", photoId);

                Photo photo = (Photo) namedSelect.queryForObject(SELECT_PHOTO_BY_ID, selectParameters,
                        new RowMapper() {
                            public Object mapRow(ResultSet resultSet, int rowNum) throws SQLException {
                                return new Photo(
                                        resultSet.getInt(PHOTO_ID),
                                        resultSet.getInt(USER_ID),
                                        resultSet.getBytes(PHOTO_DATA),
                                        resultSet.getString(PHOTO_DESCRIPTION));
                            }
                        }
                );

                //connection.close(); //TODO multiple upload 500
                logger.info("Got photo with id " + photo.getIdPhoto());
                return photo;

            } catch (SQLException e) {
                handleSqlException(e);
            } finally {
                closeConnection(connection);
            }
        }
        return null;
    }

    @Override
    public int insert(Photo photo) {
        if (photo != null) {
            connection = null;
            try {
                connection = dataSource.getConnection();
                NamedParameterJdbcTemplate namedInsert = new NamedParameterJdbcTemplate(this.dataSource);
                MapSqlParameterSource insertParameters = new MapSqlParameterSource();

                fillMapSqlParametersSourceWithData(insertParameters, photo);

                KeyHolder lastIncrement = new GeneratedKeyHolder();
                namedInsert.update(INSERT_NEW_PHOTO, insertParameters, lastIncrement, new String[]{PHOTO_ID});
                logger.info("Photo with id " + lastIncrement.getKey().intValue() + " successfully added.");
                connection.close();
                return lastIncrement.getKey().intValue();
            } catch (SQLException e) {
                handleSqlException(e);
            } finally {
                closeConnection(connection);
            }
        }
        return 0;
    }

    @Override
    public void updateDesctiption(Photo photo) {
        if (photo != null) {
            connection = null;
            try {
                connection = dataSource.getConnection();
                NamedParameterJdbcTemplate namedUpdate = new NamedParameterJdbcTemplate(this.dataSource);
                MapSqlParameterSource updateParameters = new MapSqlParameterSource();
                updateParameters.addValue(PHOTO_ID, photo.getIdPhoto());
                updateParameters.addValue(PHOTO_DESCRIPTION, photo.getImageDescription());

                namedUpdate.update(UPDATE_PHOTO_DESCRIPTION_BY_ID, updateParameters);
                logger.info("Photo with id " + photo.getIdPhoto() + " description updated.");
                connection.close();

            } catch (SQLException e) {
                handleSqlException(e);
            } finally {
                closeConnection(connection);
            }
        }
    }

    @Override
    public boolean deleteByPhotoId(int photoId) {
        if (photoId > 0) {
            connection = null;
            try {
                connection = dataSource.getConnection();
                NamedParameterJdbcTemplate namedDelete = new NamedParameterJdbcTemplate(this.dataSource);

                int count = namedDelete.update(DELETE_PHOTO_BY_ID, new MapSqlParameterSource(PHOTO_ID, photoId));

                connection.close();
                logger.info("Photo with id " + photoId + " deleted from DB.");
                return count == 1;

            } catch (SQLException e) {
                handleSqlException(e);
            } finally {
                closeConnection(connection);
            }
        }
        return false;
    }

}

redpajama_set_name: RedPajamaGithub


text:
import os
import string
import time
from django.core.files.base import ContentFile
from datetime import datetime
from django_rq import job
from django.contrib.auth.models import User
from django.utils import timezone
from dateutil.parser import parse as extract_date
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Max
from survey.utils.logger import glogger as logger
from survey.models.base import BaseModel
from survey.models.access_channels import InterviewerAccess, ODKAccess, USSDAccess
from survey.models.locations import Point
from survey.utils.decorators import static_var

class Interview(BaseModel):
    interviewer = models.ForeignKey(
        "Interviewer",
        null=True,
        related_name="interviews")  # nullable for simulation & backend load
    ea = models.ForeignKey('EnumerationArea', related_name='interviews',
                           db_index=True, null=True)  # repeated here for easy reporting
    survey = models.ForeignKey(
        'Survey',
        related_name='interviews',
        db_index=True,
        null=True)
    question_set = models.ForeignKey(
        'QuestionSet',
        related_name='interviews',
        db_index=True)
    interview_reference = models.ForeignKey(
        'Interview',
        related_name='follow_up_interviews',
        null=True,
        blank=True)
    interview_channel = models.ForeignKey(
        InterviewerAccess, related_name='interviews', null=True)
    closure_date = models.DateTimeField(null=True, blank=True, editable=False, verbose_name='Completion Date')
    # just used to capture preview/data entry tester
    uploaded_by = models.ForeignKey(User, null=True, blank=True)
    test_data = models.BooleanField(default=False)
    #instance_id = models.CharField(max_length=200, null=True, blank=True)
    last_question = models.ForeignKey("Question", related_name='ongoing', null=True, blank=True)

    def __unicode__(self):
        return '%s: %s' % (self.id, self.question_set.name)

    def is_closed(self):
        return self.closure_date is not None

    @property
    def qset(self):
        from survey.models.questions import QuestionSet
        return QuestionSet.get(pk=self.question_set.pk)

    @property
    def has_started(self):
        return self.last_question is not None

    def get_answer(self, question, capwords=True):
        answer_class = Answer.get_class(question.answer_type)
        answers = answer_class.objects.filter(interview=self, question=question)
        if answers.exists():
            reply = unicode(answers[0].to_text())
            if capwords:
                reply = string.capwords(reply)
            return reply
        return ''

    @classmethod
    def save_answers(cls, qset, survey, ea, access_channel, question_map, answers, survey_parameters={},
                     reference_interview=None, media_files={}):
        """Used to save a dictionary list of answers. keys in each answer dict must be keys in the question map
        :param qset:
        :param survey:
        :param ea:
        :param access_channel:
        :param question_map: For convinence, a dictionary containing ID to question instance {1: quest1, 2: quest2... }
        :param answers: list of dictionaries each contains the [{quest_id: answer, quest_id2: answer2, ...}, ]
        :param survey_parameters: This is a dictionary of group paramaters
        :param reference_interview: Reference interview if any
        :param media_files: Any media files available. Required for file related answers (Image, audio and video)
        :return:
        """
        # at least make sure this qset is covered
        question_map.update({question.id: question for question in qset.all_questions})
        interviewer = access_channel.interviewer
        interviews = []
        if reference_interview and (isinstance(reference_interview, Interview) is False):
            reference_interview = Interview.get(id=reference_interview)

        def _save_record(record):
            now = timezone.now()
            closure_date = record.get('completion_date', now).replace(tzinfo=now.tzinfo)
            interview = Interview.objects.create(survey=survey, question_set=qset,
                                                 ea=ea, interviewer=interviewer, interview_channel=access_channel,
                                                 closure_date=closure_date,
                                                 interview_reference=reference_interview)
            interviews.append(interview)
            map(lambda (q_id, answer): _save_answer(interview, q_id, answer), record.items())
            if survey_parameters:
                map(lambda (q_id, answer): _save_answer(interview, q_id, answer), survey_parameters.items())

        def _save_answer(interview, q_id, answer):
            try:
                question = question_map.get(q_id, None)
                if question and answer:
                    answer_class = Answer.get_class(question.answer_type)
                    if question.answer_type in [AudioAnswer.choice_name(), ImageAnswer.choice_name(),
                                                VideoAnswer.choice_name()]:
                        media = media_files.get(answer, None)
                        # only file objects or the file contents
                        answer = ContentFile(media, name=answer)
                    answer_class.create(interview, question, answer)
            except Exception, ex:
                logger.error('error saving %s, desc: %s' % (q_id, str(ex)))
        map(_save_record, answers)
        return interviews

    def respond(self, reply=None, channel=ODKAccess.choice_name(), answers_context={}):
        """
            Respond to given reply for specified channel. Irrespective to group.
            Might be depreciating group in the near future
            This method is volatile.Raises exception if some error happens in the process
        :param reply:
        :param channel:
        :return: Returns next question if any
        """
        qset = self.question_set.to_exact
        if self.is_closed():
            return
        next_question = None
        if self.has_started and reply:
            # save reply
            answer_class = Answer.get_class(self.last_question.answer_type)
            answer_class.create(self, self.last_question, reply)
            # compute nnext
            next_question = self.last_question.next_question(reply)
        elif self.has_started is False:
            self.last_question = qset.g_first_question
            self.save()
            reply = None        # ignore the initial message
        if self.has_started and reply is None:
            return self.last_question.display_text(channel=channel, context=answers_context)
        # now confirm the question is applicable
        if next_question and AnswerAccessDefinition.is_valid(channel, next_question.answer_type) is False:
            # if not get next line question
            next_question = qset.next_inline(self.last_question, channel=channel)
        response_text = None
        if next_question:
            self.last_question = next_question
            response_text = self.last_question.display_text(channel=channel, context=answers_context)
        else:
            self.closure_date = timezone.now()
        self.save()
        return response_text

    @classmethod
    def interviews_in(cls, location, survey=None, include_self=False):
        left = location.lft
        right = location.rght
        if include_self is False:
            left = left + 1
            right = right - 1
        kwargs = {'ea__locations__lft__gte': left, 'ea__locations__lft__lte': right,
                  'ea__locations__level__gte': location.level}
        if survey:
            kwargs['survey'] = survey
        return Interview.objects.filter(**kwargs)

    @classmethod
    def interviews(cls, survey):
        return Interview.objects.filter(survey=survey)

    class Meta:
        app_label = 'survey'

class Answer(BaseModel):
    STRING_FILL_LENGTH = 20
    # now question_type is used to store the exact question we are answering
    # (Listing, Batch, personal info)
    # I think using generic models is an overkill since they're all
    question_type = models.CharField(max_length=100)
    # questions
    interview = models.ForeignKey(
        Interview,
        related_name='%(class)s',
        db_index=True)
    question = models.ForeignKey(
        "Question",
        null=True,
        related_name="%(class)s",
        on_delete=models.PROTECT,
        db_index=True)
    # basically calculated field for reporting
    identifier = models.CharField(max_length=200, db_index=True)
    # basically calculated field for reporting
    as_text = models.CharField(max_length=200, db_index=True)
    # basically calculated field for reporting
    as_value = models.CharField(max_length=200, db_index=True)

    @classmethod
    def create(cls, interview, question, answer, as_text=None, as_value=None):
        if as_text is None:
            as_text = cls.prep_text(unicode(answer)[:200])
        if as_value is None:
            as_value = cls.prep_value(unicode(answer)[:200])
        return cls.objects.create(
            question=question,
            value=answer,
            question_type=question.__class__.type_name(),
            interview=interview,
            identifier=question.identifier,
            as_text=as_text,
            as_value=as_value)

    def __unicode__(self):
        return unicode(self.as_text)

    @classmethod
    def prep_value(cls, val):
        return unicode(val).lower()

    @classmethod
    def prep_text(cls, text):
        return unicode(text).lower()

    def update(self, answer):
        self.as_text = answer
        self.as_value = answer
        self.save()

    @classmethod
    def supported_answers(cls):
        supported = [cl for cl in Answer.__subclasses__() if cl not in [NonResponseAnswer, NumericalTypeAnswer]]
        supported.extend([cl for cl in NumericalTypeAnswer.__subclasses__()])
        return supported

    @classmethod
    def answer_types(cls):
        answer_types = [cl.choice_name() for cl in Answer.__subclasses__() if cl not in [NonResponseAnswer,
                                                                                NumericalTypeAnswer]]
        answer_types.extend([cl.choice_name() for cl in NumericalTypeAnswer.__subclasses__()])
        return sorted(answer_types)

    @classmethod
    def get_class(cls, verbose_name):
        verbose_name = verbose_name.strip()
        for cl in Answer.__subclasses__():
            if cl.choice_name() == verbose_name:
                return cl
        # check in numerical answer type
        for cl in NumericalTypeAnswer.__subclasses__():
            if cl.choice_name() == verbose_name:
                return cl
        raise ValueError('unknown class %s' % verbose_name)

    def to_text(self):
        return self.as_text

    def to_label(self):
        return self.as_value

    def pretty_print(self, as_label=False):
        return self.to_text()

    @classmethod
    def choice_name(cls):
        return cls._meta.verbose_name.title()

    @classmethod
    def contains(cls, answer, txt):
        answer = answer.lower()
        txt = txt.lower()
        try:
            return answer.index(txt) >= 0
        except ValueError:
            return False

    @classmethod
    def fetch_contains(cls, answer_key, txt, qs=None):
        txt = cls.prep_value(txt)
        if qs is None:
            qs = cls.objects
        return qs.filter(**{'%s__icontains' % answer_key: txt})

    @classmethod
    def odk_contains(cls, node_path, value):
        return "regex(%s, '.*(%s).*')" % (node_path, value)

    @classmethod
    def equals(cls, answer, value):
        return unicode(answer).lower() == unicode(value).lower()

    @classmethod
    def fetch_equals(cls, answer_key, value, qs=None):
        value = cls.prep_value(value)
        if qs is None:
            qs = cls.objects
        return qs.filter(**{'%s__iexact' % answer_key: unicode(value)})

    @classmethod
    def odk_equals(cls, node_path, value):
        return "%s = '%s'" % (node_path, value)

    @classmethod
    def starts_with(cls, answer, txt):
        answer = answer.lower()
        txt = txt.lower()
        return answer.startswith(txt)

    @classmethod
    def fetch_starts_with(cls, answer_key, txt, qs=None):
        txt = cls.prep_value(txt)
        if qs is None:
            qs = cls.objects
        return qs.filter(**{'%s__istartswith' % answer_key: unicode(txt)})

    @classmethod
    def odk_starts_with(cls, node_path, value):
        return "regex(%s, '^(%s).*')" % (node_path, value)

    @classmethod
    def ends_with(cls, answer, txt):
        answer = answer.lower()
        txt = txt.lower()
        return answer.endswith(txt)

    @classmethod
    def fetch_ends_with(cls, answer_key, txt, qs=None):
        txt = cls.prep_value(txt)
        if qs is None:
            qs = cls.objects
        return qs.filter(**{'%s__iendswith' % answer_key: unicode(txt)})

    @classmethod
    def odk_ends_with(cls, node_path, value):
        return "regex(%s, '.*(%s)$')" % (node_path, value)

    @classmethod
    def greater_than(cls, answer, value):
        return answer > value

    @classmethod
    def fetch_greater_than(cls, answer_key, value, qs=None):
        value = cls.prep_value(value)
        if qs is None:
            qs = cls.objects
        return qs.filter(**{'%s__gt' % answer_key: value})

    @classmethod
    def odk_greater_than(cls, node_path, value):
        return "%s > '%s'" % (node_path, value)

    @classmethod
    def less_than(cls, answer, value):
        return answer < value

    @classmethod
    def fetch_less_than(cls, answer_key, value, qs=None):
        value = cls.prep_value(value)
        if qs is None:
            qs = cls.objects
        return qs.filter(**{'%s__lt' % answer_key: value})

    @classmethod
    def odk_less_than(cls, node_path, value):
        return "%s < '%s'" % (node_path, value)

    @classmethod
    def between(cls, answer, lowerlmt, upperlmt):
        return upperlmt > answer >= lowerlmt

    @classmethod
    def get_validation_query_params(cls):
        return {cls.greater_than.__name__: 'gt', cls.less_than.__name__: 'lt',
                cls.starts_with.__name__: 'istartswith', cls.ends_with.__name__: 'iendswith',
                cls.contains.__name__: 'icontains', cls.equals.__name__: 'iexact'}

    @classmethod
    def get_validation_queries(cls, method_name, answer_key, *test_args, **kwargs):
        namespace = kwargs.pop('namespace', '')
        validation_queries = cls.get_validation_query_params()
        if method_name == cls.between.__name__:         # only between takes two arguments
            query_args = []
            return {'%s%s__%s' % (namespace, answer_key, validation_queries[cls.less_than.__name__]): test_args[1],
                    '%s%s__%s' % (namespace, answer_key,
                                  validation_queries[cls.greater_than.__name__]): test_args[0]
                    }
        else:
            return {'%s%s__%s' % (namespace, answer_key, validation_queries[method_name]): test_args[0],}
    #
    # @classmethod
    # def __getattr__(cls, name):
    #     """Shall be used to implement all fetch_validation function methods.
    #     This is required instead of implementing individual code for each. This function results in db call
    #     :param name:
    #     :return:
    #     """
    #     if name.startswith('fetch_'):
    #         method_name = name[6:]
    #
    #         def wrapper(answer_key, qs=cls.objects, *test_args):
    #             return qs.filter(**cls.get_validation_queries(method_name, answer_key, *test_args))
    #         return wrapper
    #     raise AttributeError

    @classmethod
    def fetch_between(cls, answer_key, lowerlmt, upperlmt, qs=None):
        upperlmt = cls.prep_value(upperlmt)
        lowerlmt = cls.prep_value(lowerlmt)
        if qs is None:
            qs = cls.objects
        return qs.filter(**{'%s__lt' % answer_key: upperlmt, '%s__gte' % answer_key: lowerlmt})

    @classmethod
    def odk_between(cls, node_path, lowerlmt, upperlmt):
        return "(%s > '%s') and (%s <= '%s')" % (node_path, lowerlmt, node_path, upperlmt)

    @classmethod
    def print_odk_validation(cls, node_path, validator_name, *args):
        printer = getattr(cls, 'odk_%s' % validator_name)
        return printer(node_path, *args)

    @classmethod
    def passes_test(cls, text_exp):
        return bool(eval(text_exp))

    @classmethod
    def validators(cls):
        return [
            cls.starts_with,
            cls.ends_with,
            cls.equals,
            cls.between,
            cls.less_than,
            cls.greater_than,
            cls.contains,
        ]

    @classmethod
    def validate_test_value(cls, value):
        """Shall be used to validate that a given value is appropriate for this answer
        :return:
        """
        for validator in cls._meta.get_field_by_name('value')[0].validators:
            validator(value)

    class Meta:
        app_label = 'survey'
        abstract = False
        get_latest_by = 'created'

class NumericalTypeAnswer(Answer):

    @classmethod
    def validators(cls):
        return [
            cls.equals,
            cls.between,
            cls.less_than,
            cls.greater_than,
        ]

    @classmethod
    def prep_text(cls, val):
        return unicode(val).zfill(cls.STRING_FILL_LENGTH)

    @classmethod
    def prep_value(cls, val):
        return unicode(val).zfill(cls.STRING_FILL_LENGTH)

    @classmethod
    def greater_than(cls, answer, value):
        answer = int(answer)
        value = int(value)
        return answer > value

    @classmethod
    def odk_greater_than(cls, node_path, value):
        return "%s > %s" % (node_path, value)

    @classmethod
    def less_than(cls, answer, value):
        answer = int(answer)
        value = int(value)
        return answer < value

    @classmethod
    def odk_less_than(cls, node_path, value):
        return "%s < %s" % (node_path, value)

    @classmethod
    def between(cls, answer, lowerlmt, upperlmt):
        answer = int(answer)
        upperlmt = int(upperlmt)
        lowerlmt = int(lowerlmt)
        return upperlmt > answer >= lowerlmt

    @classmethod
    def odk_between(cls, node_path, lowerlmt, upperlmt):
        return "(%s > %s) and (%s <= %s)" % (
            node_path, lowerlmt, node_path, upperlmt)

    @classmethod
    def validate_test_value(cls, value):
        try:
            int(value)
        except ValueError as ex:
            raise ValidationError([unicode(ex), ])

    class Meta:
        app_label = 'survey'
        abstract = True

class NumericalAnswer(NumericalTypeAnswer):
    value = models.PositiveIntegerField(null=True)

    @classmethod
    def create(cls, interview, question, answer):
        value = int(answer)
        text_value = cls.prep_value(value)    # zero fill to 1billion
        return super(NumericalAnswer, cls).create(interview, question, answer, as_text=value, as_value=text_value)

    class Meta:
        app_label = 'survey'
        abstract = False

class AutoResponse(NumericalTypeAnswer):
    """Shall be used to capture responses auto generated
    """
    value = models.CharField(null=True, max_length=100)

    @classmethod
    def choice_name(cls):
        return 'Auto Generated'

    class Meta:
        app_label = 'survey'
        abstract = False

    @classmethod
    def create(cls, interview, question, answer):
        """Anwer shall be auto prepended with interviewer name
                :param interview:
        :param question:
        :param answer:
        :return:
        """
        value = int(answer)
        prefix = 'flow-test'
        if interview.interview_channel:
            prefix = interview.interview_channel.user_identifier
        # zero fill to 1billion
        text_value = '%s-%s' % (prefix, cls.prep_value(value))
        return super(
            AutoResponse,
            cls).create(
            interview,
            question,
            answer,
            as_text=value,
            as_value=text_value)

class ODKGeoPoint(Point):
    altitude = models.DecimalField(decimal_places=3, max_digits=10)
    precision = models.DecimalField(decimal_places=3, max_digits=10)

    class Meta:
        app_label = 'survey'
        abstract = False

class TextAnswer(Answer):
    value = models.CharField(max_length=200, blank=False, null=False)

    class Meta:
        app_label = 'survey'
        abstract = False

    @classmethod
    def validators(cls):
        return [cls.starts_with, cls.equals, cls.ends_with, cls.contains]

    @classmethod
    def equals(cls, answer, value):
        answer = answer.lower()
        value = value.lower()
        return answer == value

class MultiChoiceAnswer(Answer):
    value = models.ForeignKey("QuestionOption", null=True)

    @classmethod
    def create(cls, interview, question, answer):
        if unicode(answer).isdigit():
            answer = int(answer)
            answer = question.options.get(order=answer)
        else:
            answer = question.options.get(text__iexact=answer)
        return super(
            MultiChoiceAnswer,
            cls).create(
            interview,
            question,
            answer,
            as_text=answer.text,
            as_value=answer.order)

    def update(self, answer):
        if unicode(answer).isdigit():
            answer = int(answer)
            answer = self.question.options.get(order=answer)
        else:
            answer = self.question.options.get(text__iexact=answer)
        self.as_text = answer.text
        self.as_value = answer.order
        self.value = answer
        self.save()

    class Meta:
        app_label = 'survey'
        abstract = False

    @classmethod
    def validators(cls):
        return [cls.equals, ]

    def to_text(self):
        return self.value.text

    def pretty_print(self, as_label=False):
        if as_label:
            return self.value.order
        else:
            return self.value.text

    @classmethod
    @static_var('label', 'Equals Option')
    def equals(cls, answer, txt):
        return super(MultiChoiceAnswer, cls).equals(answer, txt)

class MultiSelectAnswer(Answer):
    value = models.ManyToManyField("QuestionOption", )

    @classmethod
    def create(cls, interview, question, answer):
        raw_answer = answer
        if isinstance(answer, basestring):
            answer = answer.split(' ')
        if isinstance(answer, list):
            selected = [a.lower() for a in answer]
            options = question.options.all()
            chosen = [op.pk for op in options if op.text.lower() in selected]
            selected = question.options.filter(pk__in=chosen)
        else:
            selected = answer
            raw_answer = ' '.join(answer.values_list('text', flat=True))
        ans = cls.objects.create(
            question=question,
            question_type=question.__class__.type_name(),
            interview=interview,
            identifier=question.identifier,
            as_text=raw_answer,
            as_value=raw_answer)
        for opt in selected:
            ans.value.add(opt)
        return ans

    class Meta:
        app_label = 'survey'
        abstract = False

    def to_text(self):
        texts = []
        map(lambda opt: texts.append(opt.text), self.value.all())
        return ' and '.join(texts)

    def to_label(self):
        texts = []
        map(lambda opt: texts.append(unicode(opt.order)), self.value.all())
        return ' and '.join(texts)

    def pretty_print(self, as_label=False):
        if as_label:
            return self.to_label()
        else:
            return self.to_text()

    @classmethod
    def validators(cls):
        return [cls.equals, cls.contains]

    @classmethod
    def equals(cls, answer, txt):
        return answer.lower() == txt.lower()

class DateAnswer(Answer):
    value = models.DateField(null=True)

    @classmethod
    def prep_value(cls, val):
        if isinstance(val, basestring):
            val = extract_date(val, dayfirst=False)
        # prepare as integer. for saving
        date_value = int(time.mktime(val.timetuple()))
        return unicode(date_value).zfill(cls.STRING_FILL_LENGTH)

    @classmethod
    def create(cls, interview, question, answer):
        raw_answer = answer
        if isinstance(answer, basestring):
            answer = extract_date(answer, dayfirst=False)
        # use zfill to normalize the string for comparism
        return super(DateAnswer, cls).create(interview, question, answer, as_text=raw_answer,
                                             as_value=cls.prep_value(answer)
                                             )

    class Meta:
        app_label = 'survey'
        abstract = False

    @classmethod
    def validators(cls):
        return [cls.greater_than, cls.equals, cls.less_than, cls.between]

    @classmethod
    def greater_than(cls, answer, value):
        if isinstance(value, basestring):
            value = extract_date(value, dayfirst=True).date()
        if isinstance(answer, basestring):
            answer = extract_date(answer, dayfirst=True).date()
        return answer > value

    @classmethod
    def less_than(cls, answer, value):
        if isinstance(value, basestring):
            value = extract_date(value, dayfirst=True).date()
        if isinstance(answer, basestring):
            answer = extract_date(answer, dayfirst=True).date()
        return answer < value

    @classmethod
    def between(cls, answer, lowerlmt, upperlmt):
        if isinstance(answer, basestring):
            answer = extract_date(answer, dayfirst=True).date()
        if isinstance(lowerlmt, basestring):
            lowerlmt = extract_date(lowerlmt, dayfirst=True).date()
        if isinstance(upperlmt, basestring):
            upperlmt = extract_date(upperlmt, dayfirst=True).date()
        return upperlmt > answer >= lowerlmt

    @classmethod
    def to_odk_date(cls, date_val):
        if isinstance(date_val, basestring):
            date_val = extract_date(date_val, dayfirst=True)
        return "date('%s')" % date_val.strftime('%Y-%m-%d')

    @classmethod
    def odk_greater_than(cls, node_path, value):
        return "%s > %s" % (node_path, cls.to_odk_date(value))

    @classmethod
    def odk_less_than(cls, node_path, value):
        return "%s < %s" % (node_path, cls.to_odk_date(value))

    @classmethod
    def odk_between(cls, node_path, lowerlmt, upperlmt):
        return "(%s > %s) and (%s <= %s)" % (
            node_path, cls.to_odk_date(lowerlmt), node_path, cls.to_odk_date(upperlmt))

    @classmethod
    def validate_test_value(cls, value):
        '''Shall be used to validate that a given value is appropriate for this answer
        :return:
        '''
        try:
            extract_date(value, fuzzy=True)
        except ValueError as ex:
            raise ValidationError([unicode(ex), ])

class FileAnswerMixin(object):
    @classmethod
    def create(cls, interview, question, answer, as_text=None, as_value=None):
            # answer is a file object
        as_value = os.path.basename(answer.name)
        as_text = os.path.basename(answer.name)
        return cls.objects.create(
            question=question,
            value=answer,
            question_type=question.__class__.type_name(),
            interview=interview,
            identifier=question.identifier,
            as_text=as_text,
            as_value=as_value)

class AudioAnswer(FileAnswerMixin, Answer):
    value = models.FileField(upload_to=settings.ANSWER_UPLOADS, null=True)

    class Meta:
        app_label = 'survey'
        abstract = False

    @classmethod
    def validators(cls):
        return []

class VideoAnswer(FileAnswerMixin, Answer):
    value = models.FileField(upload_to=settings.ANSWER_UPLOADS, null=True)

    class Meta:
        app_label = 'survey'
        abstract = False

    @classmethod
    def validators(cls):
        return []

class ImageAnswer(FileAnswerMixin, Answer):
    value = models.FileField(upload_to=settings.ANSWER_UPLOADS, null=True)

    class Meta:
        app_label = 'survey'
        abstract = False

    @classmethod
    def validators(cls):
        return []

class GeopointAnswer(Answer):
    value = models.ForeignKey(ODKGeoPoint, null=True)

    @classmethod
    def create(cls, interview, question, answer):
        raw_answer = answer
        if isinstance(answer, basestring):
            answer = answer.split(' ')
            answer = ODKGeoPoint.objects.create(
                latitude=answer[0],
                longitude=answer[1],
                altitude=answer[2],
                precision=answer[3])
        return super(
            GeopointAnswer,
            cls).create(
            interview,
            question,
            answer,
            as_text=raw_answer,
            as_value=raw_answer)

    class Meta:
        app_label = 'survey'
        abstract = False

    @classmethod
    def validators(cls):
        return [cls.equals, ]

class NonResponseAnswer(BaseModel):
    interview = models.ForeignKey(
        Interview,
        related_name='non_response_answers',
        db_index=True)
    value = models.CharField(max_length=200, blank=False, null=False)
    interviewer = models.ForeignKey(
        "Interviewer", null=True, related_name='non_response_answers')

    class Meta:
        app_label = 'survey'
        abstract = False

    @classmethod
    def validators(cls):
        return []

    @property
    def as_text(self):
        return self.value

    @property
    def as_value(self):
        return self.value

class AnswerAccessDefinition(BaseModel):
    ACCESS_CHANNELS = [(name, name)
                       for name in InterviewerAccess.access_channels()]
    ANSWER_TYPES = [(name, name) for name in Answer.answer_types()]
    answer_type = models.CharField(max_length=100, choices=ANSWER_TYPES)
    channel = models.CharField(max_length=100, choices=ACCESS_CHANNELS)

    class Meta:
        app_label = 'survey'
        unique_together = [('answer_type', 'channel'), ]

    @classmethod
    def is_valid(cls, channel, answer_type):
        try:
            return cls.objects.get(
                answer_type=answer_type,
                channel=channel) is not None
        except cls.DoesNotExist:
            return False

    @classmethod
    def access_channels(cls, answer_type):
        return set(AnswerAccessDefinition.objects.filter(answer_type=answer_type).values_list('channel', flat=True))

    @classmethod
    def answer_types(cls, channel):
        """Returns the answer type compatible with this channel"""
        return set(
            AnswerAccessDefinition.objects.filter(
                channel=channel).values_list(
                'answer_type', flat=True))

    @classmethod
    def reload_answer_categories(cls):
        from survey.models import USSDAccess, ODKAccess, WebAccess
        cls.objects.get_or_create(channel=USSDAccess.choice_name(),
                                                     answer_type=AutoResponse.choice_name())
        cls.objects.get_or_create(channel=USSDAccess.choice_name(),
                                                     answer_type=NumericalAnswer.choice_name())
        cls.objects.get_or_create(channel=USSDAccess.choice_name(),
                                                     answer_type=TextAnswer.choice_name())
        cls.objects.get_or_create(channel=USSDAccess.choice_name(),
                                                     answer_type=MultiChoiceAnswer.choice_name())

        # ODK definition
        cls.objects.get_or_create(channel=ODKAccess.choice_name(),
                                                     answer_type=AutoResponse.choice_name())
        cls.objects.get_or_create(channel=ODKAccess.choice_name(),
                                                     answer_type=NumericalAnswer.choice_name())
        cls.objects.get_or_create(channel=ODKAccess.choice_name(),
                                                     answer_type=TextAnswer.choice_name())
        cls.objects.get_or_create(channel=ODKAccess.choice_name(),
                                                     answer_type=MultiChoiceAnswer.choice_name())
        cls.objects.get_or_create(channel=ODKAccess.choice_name(),
                                                     answer_type=MultiSelectAnswer.choice_name())
        cls.objects.get_or_create(channel=ODKAccess.choice_name(),
                                                     answer_type=ImageAnswer.choice_name())
        cls.objects.get_or_create(channel=ODKAccess.choice_name(),
                                                     answer_type=GeopointAnswer.choice_name())
        cls.objects.get_or_create(channel=ODKAccess.choice_name(),
                                                     answer_type=DateAnswer.choice_name())
        cls.objects.get_or_create(channel=ODKAccess.choice_name(),
                                                     answer_type=AudioAnswer.choice_name())
        cls.objects.get_or_create(channel=ODKAccess.choice_name(),
                                                     answer_type=VideoAnswer.choice_name())

        # web form definition
        cls.objects.get_or_create(channel=WebAccess.choice_name(),
                                                     answer_type=NumericalAnswer.choice_name())
        cls.objects.get_or_create(channel=WebAccess.choice_name(),
                                                     answer_type=TextAnswer.choice_name())
        cls.objects.get_or_create(channel=WebAccess.choice_name(),
                                                     answer_type=MultiChoiceAnswer.choice_name())
        cls.objects.get_or_create(channel=WebAccess.choice_name(),
                                                     answer_type=MultiSelectAnswer.choice_name())
        cls.objects.get_or_create(channel=WebAccess.choice_name(),
                                                     answer_type=ImageAnswer.choice_name())
        cls.objects.get_or_create(channel=WebAccess.choice_name(),
                                                     answer_type=GeopointAnswer.choice_name())
        cls.objects.get_or_create(channel=WebAccess.choice_name(),
                                                     answer_type=DateAnswer.choice_name())
        cls.objects.get_or_create(channel=WebAccess.choice_name(),
                                                     answer_type=AudioAnswer.choice_name())
        cls.objects.get_or_create(channel=WebAccess.choice_name(),
                                                     answer_type=VideoAnswer.choice_name())


text:
        Pos
        Team
        M
        W
        D
        L
        GF
        GA
        GD
        PTS

    <tr class="table__tr" ng-repeat="teamstats in leaguetable"
        ng-class="{
            'table__tr--green': $index+1 <= season.number_of_teams_to_cl,
            'table__tr--yellow': $index+1 > season.number_of_teams_to_cl && $index+1 <= season.number_of_teams_to_cl+season.number_of_teams_to_el,
            'table__tr--red': $index+1 > season.number_of_teams - season.number_of_teams_to_ld,
         }">
        {{ $index+1 }}
        {{ teamstats.team_name }}
        {{ teamstats.matchday }}
        {{ teamstats.matches_won }}
        {{ teamstats.matches_drawn }}
        {{ teamstats.matches_lost }}
        {{ teamstats.goals_for }}
        {{ teamstats.goals_against }}
        {{ teamstats.goals_diff }}
        {{ teamstats.points }}


text:
/**
 * @module ol/style/IconImage
 */

import EventTarget from '../events/Target.js';
import EventType from '../events/EventType.js';
import ImageState from '../ImageState.js';
import {createCanvasContext2D} from '../dom.js';
import {shared as iconImageCache} from './IconImageCache.js';
import {listenImage} from '../Image.js';

/**
 * @type {CanvasRenderingContext2D}
 */
let taintedTestContext = null;

class IconImage extends EventTarget {
  /**
   * @param {HTMLImageElement|HTMLCanvasElement} image Image.
   * @param {string|undefined} src Src.
   * @param {import("../size.js").Size} size Size.
   * @param {?string} crossOrigin Cross origin.
   * @param {import("../ImageState.js").default} imageState Image state.
   * @param {import("../color.js").Color} color Color.
   */
  constructor(image, src, size, crossOrigin, imageState, color) {
    super();

    /**
     * @private
     * @type {Object<number, HTMLImageElement|HTMLCanvasElement>}
     */
    this.hitDetectionImage_ = {};

    /**
     * @private
     * @type {HTMLImageElement|HTMLCanvasElement}
     */
    this.image_ = !image ? new Image() : image;

    if (crossOrigin !== null) {
      /** @type {HTMLImageElement} */ (this.image_).crossOrigin = crossOrigin;
    }

    /**
     * @private
     * @type {Object<number, HTMLCanvasElement>}
     */
    this.canvas_ = {};

    /**
     * @private
     * @type {import("../color.js").Color}
     */
    this.color_ = color;

    /**
     * @private
     * @type {?function():void}
     */
    this.unlisten_ = null;

    /**
     * @private
     * @type {import("../ImageState.js").default}
     */
    this.imageState_ = imageState;

    /**
     * @private
     * @type {import("../size.js").Size}
     */
    this.size_ = size;

    /**
     * @private
     * @type {string|undefined}
     */
    this.src_ = src;

    /**
     * @private
     */
    this.tainted_;
  }

  /**
   * @private
   * @return {boolean} The image canvas is tainted.
   */
  isTainted_() {
    if (this.tainted_ === undefined && this.imageState_ === ImageState.LOADED) {
      if (!taintedTestContext) {
        taintedTestContext = createCanvasContext2D(1, 1);
      }
      taintedTestContext.drawImage(this.image_, 0, 0);
      try {
        taintedTestContext.getImageData(0, 0, 1, 1);
        this.tainted_ = false;
      } catch (e) {
        taintedTestContext = null;
        this.tainted_ = true;
      }
    }
    return this.tainted_ === true;
  }

  /**
   * @private
   */
  dispatchChangeEvent_() {
    this.dispatchEvent(EventType.CHANGE);
  }

  /**
   * @private
   */
  handleImageError_() {
    this.imageState_ = ImageState.ERROR;
    this.unlistenImage_();
    this.dispatchChangeEvent_();
  }

  /**
   * @private
   */
  handleImageLoad_() {
    this.imageState_ = ImageState.LOADED;
    if (this.size_) {
      this.image_.width = this.size_[0];
      this.image_.height = this.size_[1];
    } else {
      this.size_ = [this.image_.width, this.image_.height];
    }
    this.unlistenImage_();
    this.dispatchChangeEvent_();
  }

  /**
   * @param {number} pixelRatio Pixel ratio.
   * @return {HTMLImageElement|HTMLCanvasElement} Image or Canvas element.
   */
  getImage(pixelRatio) {
    this.replaceColor_(pixelRatio);
    return this.canvas_[pixelRatio] ? this.canvas_[pixelRatio] : this.image_;
  }

  /**
   * @param {number} pixelRatio Pixel ratio.
   * @return {number} Image or Canvas element.
   */
  getPixelRatio(pixelRatio) {
    this.replaceColor_(pixelRatio);
    return this.canvas_[pixelRatio] ? pixelRatio : 1;
  }

  /**
   * @return {import("../ImageState.js").default} Image state.
   */
  getImageState() {
    return this.imageState_;
  }

  /**
   * @param {number} pixelRatio Pixel ratio.
   * @return {HTMLImageElement|HTMLCanvasElement} Image element.
   */
  getHitDetectionImage(pixelRatio) {
    if (!this.hitDetectionImage_[pixelRatio]) {
      if (this.isTainted_()) {
        const usedPixelRatio = this.color_ ? pixelRatio : 1;
        const width = this.size_[0];
        const height = this.size_[1];
        const context = createCanvasContext2D(
          Math.ceil(width * usedPixelRatio),
          Math.ceil(height * usedPixelRatio)
        );
        context.scale(usedPixelRatio, usedPixelRatio);
        context.fillRect(0, 0, width, height);
        this.hitDetectionImage_[pixelRatio] = context.canvas;
      } else {
        this.hitDetectionImage_[pixelRatio] = this.image_;
      }
    }
    return this.hitDetectionImage_[pixelRatio];
  }

  /**
   * Get the size of the icon (in pixels).
   * @return {import("../size.js").Size} Image size.
   */
  getSize() {
    return this.size_;
  }

  /**
   * @return {string|undefined} Image src.
   */
  getSrc() {
    return this.src_;
  }

  /**
   * Load not yet loaded URI.
   */
  load() {
    if (this.imageState_ == ImageState.IDLE) {
      this.imageState_ = ImageState.LOADING;
      try {
        /** @type {HTMLImageElement} */ (this.image_).src = this.src_;
      } catch (e) {
        this.handleImageError_();
      }
      this.unlisten_ = listenImage(
        this.image_,
        this.handleImageLoad_.bind(this),
        this.handleImageError_.bind(this)
      );
    }
  }

  /**
   * @param {number} pixelRatio Pixel ratio.
   * @private
   */
  replaceColor_(pixelRatio) {
    if (!this.color_ || this.canvas_[pixelRatio]) {
      return;
    }

    const canvas = document.createElement('canvas');
    this.canvas_[pixelRatio] = canvas;

    canvas.width = Math.ceil(this.image_.width * pixelRatio);
    canvas.height = Math.ceil(this.image_.height * pixelRatio);

    const ctx = canvas.getContext('2d');
    ctx.scale(pixelRatio, pixelRatio);
    ctx.drawImage(this.image_, 0, 0);

    if (this.isTainted_()) {
      // If reading from the canvas throws a SecurityError the same effect can be
      // achieved with globalCompositeOperation.
      // This could be used as the default, but it is not fully supported by all
      // browsers. E. g. Internet Explorer 11 does not support the multiply
      // operation and the resulting image shape will be completelly filled with
      // the provided color.
      // So this is only used as a fallback. It is still better than having no icon
      // at all.
      const c = this.color_;
      ctx.globalCompositeOperation = 'multiply';
      ctx.fillStyle = 'rgb(' + c[0] + ',' + c[1] + ',' + c[2] + ')';
      ctx.fillRect(0, 0, canvas.width, canvas.height);

      ctx.globalCompositeOperation = 'destination-in';
      ctx.drawImage(this.image_, 0, 0);
      return;
    }

    const imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    const data = imgData.data;
    const r = this.color_[0] / 255.0;
    const g = this.color_[1] / 255.0;
    const b = this.color_[2] / 255.0;

    for (let i = 0, ii = data.length; i < ii; i += 4) {
      data[i] *= r;
      data[i + 1] *= g;
      data[i + 2] *= b;
    }
    ctx.putImageData(imgData, 0, 0);
  }

  /**
   * Discards event handlers which listen for load completion or errors.
   *
   * @private
   */
  unlistenImage_() {
    if (this.unlisten_) {
      this.unlisten_();
      this.unlisten_ = null;
    }
  }
}

/**
 * @param {HTMLImageElement|HTMLCanvasElement} image Image.
 * @param {string} src Src.
 * @param {import("../size.js").Size} size Size.
 * @param {?string} crossOrigin Cross origin.
 * @param {import("../ImageState.js").default} imageState Image state.
 * @param {import("../color.js").Color} color Color.
 * @return {IconImage} Icon image.
 */
export function get(image, src, size, crossOrigin, imageState, color) {
  let iconImage = iconImageCache.get(src, crossOrigin, color);
  if (!iconImage) {
    iconImage = new IconImage(image, src, size, crossOrigin, imageState, color);
    iconImageCache.set(src, crossOrigin, color, iconImage);
  }
  return iconImage;
}

export default IconImage;


text:
function editTask(tid, name, task, inputFormat, outputFormat, bounds, time, mem, testcases, lang, code, ranges){

	lang = lang<1?1:lang>2?2:lang;

	var formHtml = '
\

\
							'+LANG['Task_name']+'\
							<input type="text" name="taskName" id="taskName" value="' + name + '">\

';
	formHtml += '
'+LANG['Formulation_of_the_problem']+'<textarea id="ttask">'+task+'</textarea>
';
	formHtml += '
'+LANG['Input_description']+'<textarea id="iformat">'+inputFormat+'</textarea>
';
	formHtml += '
'+LANG['Output_description']+'<textarea id="oformat">'+outputFormat+'</textarea>
';
	formHtml += '
'+LANG['Bounds']+'<textarea id="tbounds">'+bounds+'</textarea>
';
	formHtml += '
\
					'+LANG['Resourses']+'\

\
						'+LANG['Time']+'\

\
						1250 ms\

\

\
						'+LANG['Memory']+'\

\
						32 Mb\

\

';
	formHtml += '
'+LANG['Test_data']+'
';

	var testCounter = 1; var realTestCount = 0;
	if (testcases.length==0){
		formHtml += generateTestForm('', '', '', '', '', '');
	}
	else{
		for (var i=0; i<testcases.length; i++){
			formHtml += generateTestForm(testcases[i][0], testcases[i][1], testcases[i][2], testcases[i][3], testcases[i][4], testcases[i][5]);
		}
	}
	formHtml += '

'+LANG['Add_test']+'
';

	formHtml += '
'+LANG['Answer_template']+'
';
	formHtml += '
<input type="radio" name="chkcb" id="chkcb1"/>C/C++
';
	formHtml += '
<input type="radio" name="chkcb" id="chkcb2"/>Python
';
	formHtml += '

\

\

\

\
						 \

\

\
						 \

\

\
						 \

\

';

	if (tid >0){
		formHtml += '
'+LANG['Attention']+'
';
	}

	formHtml += '
\
					'+LANG['Save']+'\
					'+LANG['Cancel']+'\
					'+LANG['Preview']+'\

';

	function generateTestForm(tname, tinput, toutput, vname, vinput, voutput){
		if (tname == ''){tname = LANG['Test']+' '+testCounter;}
		if (vname == ''){vname = LANG['Validator']+' '+testCounter;}
		realTestCount++; testCounter++;
		return '
'+
				'
'+
					'<input name="foo" type="text" class="editable-label" placeholder="'+LANG['type_test_name']+'" value="'+tname+'" />'+
				'
'+
				'
'+
					'<textarea class="testDataArea testQuery" placeholder="Input">'+tinput+'</textarea>'+
					'<textarea class="testDataArea testAnswer" placeholder="Output">'+toutput+'</textarea>'+
				'
'+
				'
'+
					'<input name="foo" type="text" class="editable-label" placeholder="'+LANG['type_validator_name']+'" value="'+vname+'" />'+
				'
'+
				'
'+
					'<textarea class="testDataArea testQuery" placeholder="Input">'+vinput+'</textarea>'+
					'<textarea class="testDataArea testAnswer" placeholder="Output">'+voutput+'</textarea>'+
				'
'+
				'
'+LANG['Remove_test']+'
'+
			'
';
	}

	$("#frontDiv").html(formHtml);

	$("#chkcb"+lang).prop('checked', true);

	$(".dialogContainer").mCustomScrollbar({scrollbarPosition:"outside", axis:"y", theme:"rounded", autoExpandScrollbar:true, mouseWheel:{scrollAmount:350,normalizeDelta:true}});

	$("#timerange").slider({
		range: "min",
		min: 1,
		max: 10,
		value: time,
		slide: function(e, ui) {
			time = ui.value;
			$("#timeval").html((ui.value*250)+" ms");
		}
	});
	$("#timeval").html((time*250)+" ms");

	$("#memrange").slider({
		range: "min",
		min: 4,
		max: 8,
		value: mem,
		slide: function(e, ui) {
			mem = ui.value;
			$("#memval").html((1<<ui.value)+" Mb");
		}
	});
	$("#memval").html((1<<mem)+" Mb");
	if (realTestCount >= 5){$("#addTest").show();}

	var patterns = ["",
					"#include <stdio.h>\n\nint main(){\n\t\n\treturn 0;\n}",
					"print('Hello, world!')"];
	var oldCodes = patterns;
	var langCodes = ["", "c_cpp", "python"];

	var unlockButton = $("#remove-range"); $(unlockButton).hide();
	var unlockButtonHide = true;

	var editor = ace.edit("patternEditor");
	var Range = require("ace/range").Range;
	ace.require("ace/ext/language_tools");
	ace.require("ace/ext/spellcheck");
	ace.require("ace/ext/static_highlight");
	editor.setHighlightActiveLine(true);
	editor.setTheme("ace/theme/tomorrow_night");
	editor.setShowPrintMargin(false);
	var session = editor.getSession();
	session.setUseSoftTabs(false);
	session.setMode("ace/mode/"+langCodes[lang]);
	editor.setOptions({
		enableBasicAutocompletion: true,
		enableSnippets: true,
		enableMultiselect: true,
		fontSize: "14px",
		showInvisibles: false
	});
	if (code == ""){code = patterns[lang];}
	session.getDocument().setValue(code);
	session.setUndoManager(new ace.UndoManager());

	editor.selection.on("changeSelection", function(){
		var range = editor.getSelectionRange();
		var intersect = intersects(range);
		if (unlockButtonHide && intersect){
			unlockButtonHide=false; $(unlockButton).show();
		}
		else if ( ! (unlockButtonHide||intersect)){
			unlockButtonHide=true;  $(unlockButton).hide();
		}
	});

	var rangeList = [];
	for (var i=0; i<ranges.length; i++){
		addMarker(new Range(ranges[i][0], ranges[i][1], ranges[i][2], ranges[i][3]));
	}
	$("#add-range").click(function(){ if (addMarker()) {unlockButtonHide=false; $(unlockButton).show();} });
	$("#remove-range").click(function(){ unlockButtonHide=true; $(unlockButton).hide(); removeMarker();});
	$("#restore").click(function(){ unlockButtonHide=true; $(unlockButton).hide(); removeAllMarkers(); session.getDocument().setValue(patterns[lang]);});

	function addMarker(range = null){
		var range = range || editor.selection.getRange();
		if (range.start.column != range.end.column || range.start.row != range.end.row){
			removeMarker(range);
			var markerId = session.addMarker(range, "readonly-highlight");
			range.start  = session.doc.createAnchor(range.start);
			range.end    = session.doc.createAnchor(range.end);
			range.end.$insertRight = true;
			rangeList.push([range, markerId]);
			return true;
		}
		return false;
	}

	function removeMarker(range = null){
		var range = range || editor.selection.getRange();
		var res = intersects(range, true);
		for (var i=0; i<res.length; i++){
			session.removeMarker(rangeList[res[i]][1]);
			rangeList.splice(res[i], 1);
		}
	}
	function removeAllMarkers(){
		for (var i=rangeList.length - 1; i>=0; i--){
			session.removeMarker(rangeList[i][1]);
		}
		rangeList = [];
	}

	function intersects(range, list=false) {
		var r = editor.getSelectionRange();
		var res = [];
		for (var i=rangeList.length - 1; i>=0; i--){
			if (r.intersects(rangeList[i][0])){
				res.push(i);
			}
		}
		if (list == false){ return res.length>0;}
		else{ return res;}
	}

	$("#frontDiv").show();

	$("#addTest").click(function(){
		$(".testContainer").append(generateTestForm('', '', '', '', '', ''));
		$(".delete-test").off("click").click(function(){$(this).parent().parent().remove(); realTestCount--; if (realTestCount<1){$("#addTest").click();} if (realTestCount == 4){$("#addTest").show();}});
		if (realTestCount >= 5){$("#addTest").hide();}
	})
	$(".delete-test").click(function(){$(this).parent().parent().remove(); realTestCount--; if (realTestCount<1){$("#addTest").click();} if (realTestCount == 4){$("#addTest").show();}});

	$("#closePopup").click(closePopup);
	$(".dialogContainer").click(function(event){ event.stopPropagation();});
	$(".popupFilter").click(closePopup);

	$('input[type=radio][name=chkcb]').click(function(){
		oldCodes[lang] = editor.getSession().getDocument().getAllLines().join('\n');
		lang = parseInt($(this).attr('id').substr(5), 10);
		session.setMode("ace/mode/"+langCodes[lang]);
		unlockButtonHide=true; $(unlockButton).hide();
		removeAllMarkers(); session.getDocument().setValue(oldCodes[lang]);
	});

	$("#saveButton").click(function(){
		function checkValue(el){
			if ($(el).val() == ""){ $(".dialogContainer").mCustomScrollbar("scrollTo", $(el)); $(el).focus(); return false; }
			else{return true;}
		}
		var flag = true;

		var tname = $("#taskName").val(); if (!checkValue($("#taskName"))){return false;}

		var task = $("#ttask").val();
		var iformat = $("#iformat").val();
		var oformat = $("#oformat").val();
		var tbounds = $("#tbounds").val();

		if ( task == "" && (iformat == "" || oformat == "") && !checkValue($("#ttask"))){return false;}
		var timerange = time;
		var memrange = mem;

		var testNames = [];
		var testQuery = [];
		var testAnswer = [];
		$(".editable-label").each(function(){
			var v = $(this).val(); if (!checkValue($(this))){flag = false;return false;}; testNames.push(v);
		}); if (flag == false){return false;}

		$(".testQuery").each(function(){
			var v = $(this).val(); if (!checkValue($(this))){flag = false;return false;} testQuery.push(v);
		}); if (flag == false){return false;}

		$(".testAnswer").each(function(){
			var v = $(this).val(); if (!checkValue($(this))){flag = false;return false;} testAnswer.push(v);
		}); if (flag == false){return false;}

		//console.log(tname, task, iformat, oformat, tbounds, timerange, memrange, testNames, testQuery, testAnswer);
		var statement = [task, iformat, oformat, tbounds];
		var testCount = testNames.length;
		var ranges = []; var publicity = [];
		for (var i=0; i<testCount; i++){
			publicity.push((i+1)%2);
		}
		for (var i=0; i<rangeList.length; i++){
			ranges.push([rangeList[i][0].start.row, rangeList[i][0].start.column, rangeList[i][0].end.row, rangeList[i][0].end.column]);
		}

		lang = parseInt($('input[type=radio][name=chkcb]:checked').attr('id').substr(5), 10);

		var xhttp = new XMLHttpRequest();
		if (tid == -1){
			xhttp.onreadystatechange = function() {
				if (this.readyState == 4 && this.status == 200) {
					var res = parseInt(this.responseText);
					if ($(".taskItem").length > 0){
						if (res>0){
							$(".clist").append('
\

\

\
										\
										'+tname+'\

\

\
										0\
										'+testCount+'\

\

\

\
									\
									\
									\

\

');
						}
						closePopup();
					}
					else{
						location.reload();
					}
				}
			};
			var cid = $("#plus").attr('course-id');
			xhttp.open("POST", "controller.php?act=createTask", true);
			xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			xhttp.send("cid="+encodeURIComponent(cid)+"&tname="+encodeURIComponent(tname)+"&statement="+encodeURIComponent(JSON.stringify(statement))+"&testCount="+encodeURIComponent(testCount)+"&testNames="+encodeURIComponent(JSON.stringify(testNames))+"&testData="+encodeURIComponent(JSON.stringify(testQuery))+"&testAnswer="+encodeURIComponent(JSON.stringify(testAnswer))+"&publicity="+encodeURIComponent(JSON.stringify(publicity))+"&timeLimit="+encodeURIComponent(timerange)+"&memoryLimit="+encodeURIComponent(memrange)+"&lid="+encodeURIComponent(lang)+"&pattern="+encodeURIComponent(editor.getSession().getDocument().getAllLines().join('\n'))+"&ranges="+encodeURIComponent(JSON.stringify(ranges)));
		}
		else{
			xhttp.onreadystatechange = function() {
				if (this.readyState == 4 && this.status == 200) {
					$("[task-id='"+tid+"']").find(".tname").text(tname);
					closePopup();
				}
			};
			xhttp.open("POST", "controller.php?act=editTask", true);
			xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
			xhttp.send("tid="+encodeURIComponent(tid)+"&tname="+encodeURIComponent(tname)+"&statement="+encodeURIComponent(JSON.stringify(statement))+"&testCount="+encodeURIComponent(testCount)+"&testNames="+encodeURIComponent(JSON.stringify(testNames))+"&testData="+encodeURIComponent(JSON.stringify(testQuery))+"&testAnswer="+encodeURIComponent(JSON.stringify(testAnswer))+"&publicity="+encodeURIComponent(JSON.stringify(publicity))+"&timeLimit="+encodeURIComponent(timerange)+"&memoryLimit="+encodeURIComponent(memrange)+"&lid="+encodeURIComponent(lang)+"&pattern="+encodeURIComponent(editor.getSession().getDocument().getAllLines().join('\n'))+"&ranges="+encodeURIComponent(JSON.stringify(ranges)));
		}
	});

	$("#previewButton").click(function(){
		var previewText = "";

		var task = $("#ttask").val();
		var iformat = $("#iformat").val();
		var oformat = $("#oformat").val();
		var tbounds = $("#tbounds").val();
		var testQuery = $(".testQuery").val();
		var testAnswer = $(".testAnswer").val();

		if (task != ""){
			previewText += "###"+LANG['Task']+"\n"+task+"\n\n";
		}
		if (iformat != "" && oformat != ""){
			previewText += "###"+LANG['Input_format']+"\n"+iformat+"\n\n###"+LANG['Output_format']+"\n"+oformat+"\n\n";
			if (tbounds != ""){
				previewText += "###"+LANG['Bounds']+"\n"+tbounds+"\n\n";
			}
		}
		previewText += "###"+LANG['Resourses']+"\n- "+LANG['Time']+" : "+(time*250)+" ms\n- "+LANG['Memory']+" : "+(1<<mem)+" Mb\n";

		if (testQuery != "" && testAnswer != ""){
			testQuery  = testQuery.replace(/\r?\n/g, "
");
			testAnswer = testAnswer.replace(/\r?\n/g, "
");
			previewText += "\n| Input | Output |\n|--|--|\n|"+testQuery+"|"+testAnswer+"|\n";
			if ($(".testQuery").length>2){
				var testQuery = $($(".testQuery").get(2)).val();
				var testAnswer = $($(".testAnswer").get(2)).val();
				if (testQuery != "" && testAnswer != ""){
					testQuery  = testQuery.replace(/\r?\n/g, "
");
					testAnswer = testAnswer.replace(/\r?\n/g, "
");
					previewText += "|"+testQuery+"|"+testAnswer+"|\n";
				}
			}
		}

		if (previewText == ""){previewText = '
'+LANG['Nothing_to_display']+'
'}
		$("body").append('
\

\

'+''+'
\

\
					'+LANG['Close']+'\

\

');

		var converter = new showdown.Converter({tables:true});
		$(".previewText").html(converter.makeHtml(previewText));

		MathJax.Hub.Queue(["Typeset",MathJax.Hub]);

		$('pre code').each(function(i, block) {hljs.highlightBlock(block);});

		setTimeout( function(){$("#previewDialog").mCustomScrollbar({scrollbarPosition:"outside", axis:"y", theme:"light-thin", autoHideScrollbar:true, mouseWheel:{scrollAmount:200,normalizeDelta:true}})}, 500);
		$("#closePreview").click(function(){$("#previewDiv").remove();});
		$("#previewDiv").click(function(){$("#previewDiv").remove();});
		$("#previewDialog").click(function(event){ event.stopPropagation();});
	});
}