text:
'use strict';

var PATH = require('./path'),
    FS = require('fs'),
    INHERIT = require('inherit'),
    createTech = require('./tech').createTech,
    U = require('util'),
    bemUtil = require('./util'),
    LOGGER = require('./logger'),
    isRequireable = bemUtil.isRequireable,

    BEM,

    // Use this as a function because of circular dependency which occurs
    // if require is placed in the global scope of the module. BEM is also cached
    // in a var to avoid require call every time (which is much slower than if statement.
    getBem = function() {
        if (!BEM) BEM = require('..');

        return BEM;
    },

    getLevelClass = function(path, optional, stack) {
        stack = stack || [];

        var level;
        try {
            level = optional && !isRequireable(path) ? {} : requireLevel(path);
        } catch(error) {
            throw new Error(U.format(
                'level module %s can not be found %s %s%s\n',
                path,
                stack.length > 0? 'but required by the level': '',
                stack.length > 1? 'inheritance tree:\n\t': '',
                stack.join('\n\t')));
        }

        stack.push(path);

        if (typeof level === 'function') level = level(getBem());

        if (level.Level) return level.Level;

        var baseLevelPath = (level.baseLevelName?
            PATH.join(__dirname, 'levels', level.baseLevelName):
            null) || level.baseLevelPath;

        return INHERIT(baseLevelPath? getLevelClass(baseLevelPath, false, stack) : Level, level);
    },

    requireLevel = function(path) {
        return bemUtil.requireWrapper(require)(path, true);
    },

    checkedLevels = {},

    checkLevel = function(path) {
        if (checkedLevels[path]) {
            return;
        }
        checkedLevels[path] = true;
        if (!bemUtil.isDirectory(path)) {
            LOGGER.fwarn('Level at %s is not a directory', path);
            return;
        }
        if (!bemUtil.isDirectory(PATH.join(path, '.bem'))) {
            LOGGER.fwarn('Level at %s does not contain .bem subdirectory', path);
        }
    },

    levelCache = {},
    useCache = false,
    exceptLevels = [],

    allRe = /(?:^([^_.\/]+)\/__([^_.\/]+)\/(?:_([^_.\/]+)\/\1__\2_\3(?:_([^_.\/]+))?|\1__\2)(.*?)$|^([^_.\/]+)\/(?:(?:\6)|(?:_([^_.\/]+)\/\6_\7(?:_([^_.\/]+))?))(.*?)$)/,
    elemAllRe = /^([^_.\/]+)\/__([^_.\/]+)\/(?:_([^_.\/]+)\/\1__\2_\3(?:_([^_.\/]+))?|\1__\2)(.*?)$/,
    blockAllRe = /^([^_.\/]+)\/(?:(?:\1)|(?:_([^_.\/]+)\/\1_\2(?:_([^_.\/]+))?))(.*?)$/;

/**
 * Create level object from path on filesystem.
 *
 * @param {String | Object} level Path to level directory.
 * @param {Object} [opts] Optional parameters
 * @return {Level}  Level object.
 */
exports.createLevel = function(level, opts) {
    // NOTE: в директории .bem внутри уровня переопределения
    // лежит модуль-конфиг для уровня переопределения
    var path = level.path || level;

    opts = opts || {};

    checkLevel(level);

    if (!opts.noCache && levelCache[path]) return levelCache[path];
    level = new (getLevelClass(PATH.resolve(path, '.bem', 'level.js'), true))(level, opts);
    levelCache[path] = level;

    return level;
};

exports.setCachePolicy = function(useCacheByDefault, except) {
    useCache = useCacheByDefault;
    exceptLevels = except || [];
};

exports.resetLevelsCache = function(all) {
    for(var l in levelCache) {
        var level = levelCache[l];

        if (!level.cache || all) level.files = null;
    }
};

var Level = exports.Level = INHERIT(/** @lends Level.prototype */{

    /**
     * Construct an instance of Level.
     *
     * @class Level base class.
     * @constructs
     * @param {String | Object} path  Level directory path.
     * @param {Object} [opts] Optional parameters
     */
    __constructor: function(path, opts) {
        opts = opts || {};
        this.dir = PATH.resolve(path.path || path);
        this.projectRoot = opts.projectRoot || PATH.resolve('');

        // NOTE: keep this.path for backwards compatibility
        this.path = this.bemDir = PATH.join(this.dir, '.bem');

        path = PATH.relative(this.projectRoot, this.dir);
        this.cache = useCache;
        for(var e in exceptLevels) {
            var except = exceptLevels[e];
            if (path.substr(0, except.length) === except) {
                this.cache = !this.cache;
                break;
            }
        }

        // NOTE: tech modules cache
        this._techsCache = {};
    },

    /**
     * Return level type.
     *
     * Default is `['level']`.
     *
     * @return {String[]}
     */
    getTypes: function() {
        return ['level'];
    },

    /**
     * Place to store uncommon level configurations
     *
     * @return {Object}
     */
    getConfig: function() {
        return {};
    },

    /**
     * Tech module definitions for level
     *
     * @return {Object} Tech module definitions
     */
    getTechs: function() {
        // NOTE: this.techs is for backwards compatibility with legacy level configs
        return this.techs || {};
    },

    /**
     * Get tech object from its name and optional path to tech module.
     *
     * Object will be created and stored in cache. All following calls
     * to getTech() with same name will return the same object.
     *
     * Is you need unique object every time, use createTech() method
     * with same signature.
     *
     * @param {String} name  Tech name
     * @param {String} [path]  Path to tech module
     * @return {Tech}
     */
    getTech: function(name, path) {
        if(!this._techsCache.hasOwnProperty(name)) {
            this._techsCache[name] = this.createTech(name, path || name);
        }
        return this._techsCache[name];
    },

    /**
     * Create tech object from its name and optional path to tech module.
     *
     * @param {String} name  Tech name
     * @param {String} [path]  Path to tech module
     * @return {Tech}
     */
    createTech: function(name, path) {
        return createTech(this.resolveTech(path || name), name, this);
    },

    /**
     * Resolve tech identifier into tech module path.
     *
     * @param {String} techIdent  Tech identifier.
     * @param {Object|Boolean} [opts]  Options to use during resolution. If boolean value
     * is passed, it gets used as `options.force` for backward compatibility.
     * @param {Boolean} [opts.force=false] Flag to not use tech name resolution.
     * @param {Boolean} [opts.throwWhenUnresolved=false] Throw an error, if tech cannot be
     * resoled. If false, will return base tech instead of unresolved.
     * @param {Number} [version=1] Version of a tech to load, for bem-tools techs.
     * @return {String}  Tech module path.
     */
    resolveTech: function(techIdent, opts) {
        if (typeof opts === 'boolean') {
            //legacy code used `force` second argument
            opts = {force: opts};
        }
        opts = opts || {};
        if(bemUtil.isPath(techIdent)) {
            return this.resolveTechPath(techIdent);
        }
        if(!opts.force && this.getTechs().hasOwnProperty(techIdent)) {
            return this.resolveTechName(techIdent);
        }
        return bemUtil.getBemTechPath(techIdent, opts);
    },

    /**
     * Resolve tech name into tech module path.
     *
     * @param {String} techName  Tech name.
     * @return {String}  Tech module path.
     */
    resolveTechName: function(techName) {
        var p = this.getTechs()[techName];
        return typeof p !== 'undefined'? this.resolveTech(p, {force: true}) : null;
    },

    /**
     * Resolve tech module path.
     *
     * @throws {Error}  In case when tech module is not found.
     * @param {String} techPath  Tech path (relative or absolute).
     * @return {String}  Tech module path.
     */
    resolveTechPath: function(techPath) {
        // Get absolute path if path starts with "."
        // NOTE: Can not replace check to !isAbsolute()
        if(techPath.substring(0, 1) === '.') {
            // Resolve relative path starting at level `.bem/` directory
            techPath = PATH.join(this.bemDir, techPath);

            /* jshint -W109 */
            if(!isRequireable(techPath)) {
                throw new Error("Tech module on path '" + techPath + "' not found");
            }
            /* jshint +W109 */

            return techPath;
        }

        // Trying absolute of relative-without-dot path
        if(isRequireable(techPath)) {
            return techPath;
        }

        /* jshint -W109 */
        try {
            return require.resolve('./' + PATH.join('./techs', techPath));
        } catch (err) {
            throw new Error("Tech module with path '" + techPath + "' not found on require search paths");
        }
        /* jshint +W109 */
    },

    /**
     * Get list of default techs to create with `bem create {block,elem,mod}`
     * commands.
     *
     * Returns all declared techs in `defaultTechs` property or keys of result
     * of `getTech()` method if `defaultTechs` is undefined.
     *
     * @return {String[]}  Array of tech names.
     */
    getDefaultTechs: function() {
        return this.defaultTechs || Object.keys(this.getTechs());
    },

    /**
     * Resolve relative paths using level config directory `.bem/`
     * as a base for them.
     *
     * Absolute paths (and keys of object) will be left untouched.
     * Returns new Array of strings or Object.
     *
     * @param {Object|String[]} paths  Paths to resolve.
     * @return {Object|String[]}  Resolved paths.
     */
    resolvePaths: function(paths) {

        // resolve array of paths
        if (Array.isArray(paths)) {
            return paths.map(function(path) {
                return this.resolvePath(path);
            }, this);
        }

        // resolve paths in object values
        var resolved = {};
        Object.keys(paths).forEach(function(key) {
            resolved[key] = this.resolvePath(paths[key]);
        }, this);

        return resolved;

    },

    /**
     * Resolve relative path using level config directory `.bem/`
     * as a base.
     *
     * Absolute path will be left untouched.
     *
     * @param {String} path  Path to resolve.
     * @return {String}  Resolved path.
     */
    resolvePath: function(path) {
        return PATH.resolve(this.path, path);
    },

    /**
     * Construct path to tech file / directory from
     * prefix and tech name.
     *
     * @param {String} prefix  Path prefix.
     * @param {String} tech  Tech name.
     * @return {String}  Absolute path.
     */
    getPath: function(prefix, tech) {
        return this.getTech(tech).getPath(prefix);
    },

    getPaths: function(prefix, tech) {
        return (typeof tech === 'string'? this.getTech(tech): tech).getPaths(prefix);
    },

    /**
     * Construct absolute path to tech file / directory from
     * BEM entity object and tech name.
     *
     * @param {Object} item  BEM entity object.
     * @param {String} item.block  Block name.
     * @param {String} item.elem   Element name.
     * @param {String} item.mod    Modifier name.
     * @param {String} item.val    Modifier value.
     * @param {String} tech  Tech name.
     * @return {String}  Absolute path.
     */
    getPathByObj: function(item, tech) {
        return PATH.join(this.dir, this.getRelPathByObj(item, tech));
    },

    /**
     * Construct relative path to tech file / directory from
     * BEM entity object and tech name.
     *
     * @param {Object} item  BEM entity object.
     * @param {String} item.block  Block name.
     * @param {String} item.elem   Element name.
     * @param {String} item.mod    Modifier name.
     * @param {String} item.val    Modifier value.
     * @param {String} tech  Tech name.
     * @return {String}  Relative path.
     */
    getRelPathByObj: function(item, tech) {
        return this.getPath(this.getRelByObj(item), tech);
    },

    getFileByObjIfExists: function(item, tech) {
        if (!this.files) return;

        var blocks = this.files.tree,
            block = blocks[item.block];

        if (!block) return [];

        if (item.mod && !item.elem) {
            block = block.mods[item.mod];
            if (block && item.val) block = block.vals[item.val];

        } else if (item.elem) {
            block = block.elems[item.elem];
            if (block && item.mod) {
                block = block.mods[item.mod];
                if (block && item.val) block = block.vals[item.val];
            }
        }

        var files = block? block.files: null;

        if (!files || files.length === 0) return [];

        var suffixes = tech.getSuffixes(),
            res = [];

        for(var i = 0; i < suffixes.length; i++) {
            var suffix = suffixes[i],
                filesBySuffix = files[suffix];

            if (filesBySuffix) res = res.concat(filesBySuffix);

        }

        return res;
    },

    /**
     * Get absolute path prefix on the filesystem to specified
     * BEM entity described as an object with special properties.
     *
     * @param {Object} item  BEM entity object.
     * @param {String} item.block  Block name.
     * @param {String} item.elem   Element name.
     * @param {String} item.mod    Modifier name.
     * @param {String} item.val    Modifier value.
     * @return {String}  Absolute path prefix.
     */
    getByObj: function(item) {
        return PATH.join(this.dir, this.getRelByObj(item));
    },

    /**
     * Get relative to level directory path prefix on the filesystem
     * to specified BEM entity described as an object with special
     * properties.
     *
     * @param {Object} item  BEM entity object.
     * @param {String} item.block  Block name.
     * @param {String} item.elem   Element name.
     * @param {String} item.mod    Modifier name.
     * @param {String} item.val    Modifier value.
     * @return {String}  Relative path prefix.
     */
    getRelByObj: function(item) {
        var getter, args;
        if (item.block) {
            getter = 'block';
            args = [item.block];
            if (item.elem) {
                getter = 'elem';
                args.push(item.elem);
            }
            if (item.mod) {
                getter += '-mod';
                args.push(item.mod);
                if (item.val) {
                    getter += '-val';
                    args.push(item.val);
                }
            }
            return this.getRel(getter, args);
        }
        return '';
    },

    /**
     * Get absolute path prefix on the filesystem to specified
     * BEM entity described as a pair of entity type and array.
     *
     * @param {String} what  BEM entity type.
     * @param {String[]} args  Array of BEM entity meta.
     * @return {String}
     */
    get: function(what, args) {
        return PATH.join(this.dir, this.getRel(what, args));
    },

    /**
     * Get relative to level directory path prefix on the
     * filesystem to specified BEM entity described as a pair
     * of entity type and array.
     *
     * @param what
     * @param args
     * @return {String}
     */
    getRel: function(what, args) {
        return this['get-' + what].apply(this, args);
    },

    /**
     * Get relative path prefix for block.
     *
     * @param {String} block  Block name.
     * @return {String}  Path prefix.
     */
    'get-block': function(block) {
        return PATH.join.apply(null, [block, block]);
    },

    /**
     * Get relative path prefix for block modifier.
     *
     * @param {String} block  Block name.
     * @param {String} mod  Modifier name.
     * @return {String}  Path prefix.
     */
    'get-block-mod': function(block, mod) {
        return PATH.join.apply(null,
            [block,
            '_' + mod,
            block + '_' + mod]);
    },

    /**
     * Get relative path prefix for block modifier-with-value.
     *
     * @param {String} block  Block name.
     * @param {String} mod  Modifier name.
     * @param {String} val  Modifier value.
     * @return {String}  Path prefix.
     */
    'get-block-mod-val': function(block, mod, val) {
        return PATH.join.apply(null,
            [block,
            '_' + mod,
            block + '_' + mod + '_' + val]);
    },

    /**
     * Get relative path prefix for elem.
     *
     * @param {String} block  Block name.
     * @param {String} elem  Element name.
     * @return {String}  Path prefix.
     */
    'get-elem': function(block, elem) {
        return PATH.join.apply(null,
            [block,
            '__' + elem,
            block + '__' + elem]);
    },

    /**
     * Get relative path prefix for element modifier.
     *
     * @param {String} block  Block name.
     * @param {String} elem  Element name.
     * @param {String} mod  Modifier name.
     * @return {String}  Path prefix.
     */
    'get-elem-mod': function(block, elem, mod) {
        return PATH.join.apply(null,
            [block,
            '__' + elem,
            '_' + mod,
            block + '__' + elem + '_' + mod]);
    },

    /**
     * Get relative path prefix for element modifier-with-value.
     *
     * @param {String} block  Block name.
     * @param {String} elem  Element name.
     * @param {String} mod  Modifier name.
     * @param {String} val  Modifier value.
     * @return {String}  Path prefix.
     */
    'get-elem-mod-val': function(block, elem, mod, val) {
        return PATH.join.apply(null,
            [block,
            '__' + elem,
            '_' + mod,
            block + '__' + elem + '_' + mod + '_' + val]);
    },

    /**
     * Get regexp string to match parts of path that represent
     * BEM entity on filesystem.
     *
     * @return {String}
     */
    matchRe: function() {
        return '[^_.' + PATH.dirSepRe + ']+';
    },

    /**
     * Get order of matchers to apply during introspection.
     *
     * @return {String[]}  Array of matchers names.
     */
    matchOrder: function() {

        return ['elem-all', 'block-all', 'elem-mod-val', 'elem-mod', 'block-mod-val',
            'block-mod', 'elem', 'block'];
    },

    /**
     * Get order of techs to match during introspection.
     *
     * @return {String[]}  Array of techs names.
     */
    matchTechsOrder: function() {
        return Object.keys(this.getTechs());
    },

    /**
     * Match path against all matchers and return first match.
     *
     * Match object will contain `block`, `suffix` and `tech` fields
     * and can also contain any of the `elem`, `mod` and `val` fields
     * or all of them.
     *
     * @param {String} path  Path to match (absolute or relative).
     * @return {Boolean|Object}  BEM entity object in case of positive match and false otherwise.
     */
    matchAny: function(path) {
        if (PATH.isAbsolute(path)) path = PATH.relative(this.dir, path);

        var matchTechs = this.matchTechsOrder().map(function(t) {
                return this.getTech(t);
            }, this);

        return this.matchOrder().reduce(function(match, matcher) {

            // Skip if already matched
            if (match) return match;

            // Try matcher
            match = this.match(matcher, path);

            // Skip if not matched
            if (!match) return false;

            // Try to match for tech
            match.tech = matchTechs.reduce(function(tech, t) {
                if (tech || !t.matchSuffix(match.suffix)) return tech;
                return t.getTechName();
            }, match.tech);

            return match;

        }.bind(this), false);
    },

    /**
     * Match ralative path against specified matcher.
     *
     * Match object will contain `block` and `suffix` fields and
     * can also contain any of the `elem`, `mod` and `val` fields
     * or all of them.
     *
     * @param {String} what  Matcher to match against.
     * @param {String} path  Path to match.
     * @return {Boolean|Object}  BEM entity object in case of positive match and false otherwise.
     */
    match: function(what, path) {
        return this['match-' + what].call(this, path);
    },

    /**
     * Match if specified path represents block entity.
     *
     * Match object will contain `block` and `suffix` fields.

     * @param {String} path  Path to match.
     * @return {Boolean|Object}  BEM block object in case of positive match and false otherwise.
     */
    'match-block': function(path) {
        var match = new RegExp(['^(' + this.matchRe() + ')',
            '\\1(.*?)$'].join(PATH.dirSepRe)).exec(path);

        if (!match) return false;
        return {
            block: match[1],
            suffix: match[2]
        };
    },

    /**
     * Match if specified path represents block modifier entity.
     *
     * Match object will contain `block`, `mod` and `suffix` fields.
     *
     * @param {String} path  Path to match.
     * @return {Boolean|Object}  BEM block modifier object in case of positive match and false otherwise.
     */
    'match-block-mod': function(path) {
        var m = this.matchRe(),
            match = new RegExp(['^(' + m + ')',
            '_(' + m + ')',
            '\\1_\\2(.*?)$'].join(PATH.dirSepRe)).exec(path);

        if (!match) return false;
        return {
            block: match[1],
            mod: match[2],
            suffix: match[3]
        };
    },

    /**
     * Match if specified path represents block modifier-with-value entity.
     *
     * Match object will contain `block`, `mod`, `val` and `suffix` fields.
     *
     * @param {String} path  Path to match.
     * @return {Boolean|Object}  BEM block modifier-with-value object in case of positive match and false otherwise.
     */
    'match-block-mod-val': function(path) {
        var m = this.matchRe(),
            match = new RegExp(['^(' + m + ')',
            '_(' + m + ')',
            '\\1_\\2_(' + m + ')(.*?)$'].join(PATH.dirSepRe)).exec(path);

        if (!match) return false;
        return {
            block: match[1],
            mod: match[2],
            val: match[3],
            suffix: match[4]
        };
    },

    'match-block-all': function(path) {
        var match = blockAllRe.exec(path);
        if (!match) return false;

        var res =  {
            block: match[1]
        };

        if (match[2]) {
            res.mod = match[2];

            if (match[3]) res.val = match[3];
        }

        if (match[4]) res.suffix = match[4];

        return res;
    },

    'get-block-all': function() {

    },

    'get-elem-all': function() {

    },

    /**
     * Match if specified path represents element entity.
     *
     * Match object will contain `block`, `elem` and `suffix` fields.
     *
     * @param {String} path  Path to match.
     * @return {Boolean|Object}  BEM element object in case of positive match and false otherwise.
     */
    'match-elem': function(path) {
        var m = this.matchRe(),
            match = new RegExp(['^(' + m + ')',
            '__(' + m + ')',
            '\\1__\\2(.*?)$'].join(PATH.dirSepRe)).exec(path);

        if (!match) return false;
        return {
            block: match[1],
            elem: match[2],
            suffix: match[3]
        };
    },

    /**
     * Match if specified path represents element modifier entity.
     *
     * Match object will contain `block`, `elem`, `mod` and `suffix` fields.
     *
     * @param {String} path  Path to match.
     * @return {Boolean|Object}  BEM element modifier object in case of positive match and false otherwise.
     */
    'match-elem-mod': function(path) {
        var m = this.matchRe(),
            match = new RegExp(['^(' + m + ')',
            '__(' + m + ')',
            '_(' + m + ')',
            '\\1__\\2_\\3(.*?)$'].join(PATH.dirSepRe)).exec(path);

        if (!match) return false;
        return {
            block: match[1],
            elem: match[2],
            mod: match[3],
            suffix: match[4]
        };
    },

    /**
     * Match if specified path represents element modifier-with-value entity.
     *
     * Match object will contain `block`, `elem`, `mod`, `val` and `suffix` fields.
     *
     * @param {String} path  Path to match.
     * @return {Boolean|Object}  BEM element modifier-with-value object in case of positive match and false otherwise.
     */
    'match-elem-mod-val': function(path) {
        var m = this.matchRe(),
            match = new RegExp(['^(' + m + ')',
            '__(' + m + ')',
            '_(' + m + ')',
            '\\1__\\2_\\3_(' + m + ')(.*?)$'].join(PATH.dirSepRe)).exec(path);

        if (!match) return false;
        return {
            block: match[1],
            elem: match[2],
            mod: match[3],
            val: match[4],
            suffix: match[5]
        };
    },

    'match-elem-all': function(path) {
        var match = elemAllRe.exec(path);
        if (!match) return false;

        var res =  {
            block: match[1],
            elem: match[2]
        };

        if (match[3]) res.mod = match[3];
        if (match[4]) res.val = match[4];
        if (match[5]) res.suffix = match[5];

        return res;
    },

    'match-all': function(path) {
        var match = allRe.exec(path);
        if (!match) return false;

        var res = {};

        if (match[1]) {
            res.block = match[1];
            res.elem = match[2];

            if (match[3]) res.mod = match[3];
            if (match[4]) res.val = match[4];
            if (match[5]) res.suffix = match[5];
        } else if (match[6]) {

            res.block = match[6];

            if (match[7]) {
                res.mod = match[7];

                if (match[8]) res.val = match[8];
            }

            if (match[9]) res.suffix = match[9];
        }

        return res;
    },

    /**
     * Get declaration for block.
     *
     * @param {String} blockName  Block name to get declaration for.
     * @return {Object}  Block declaration object.
     */
    getBlockByIntrospection: function(blockName) {
        // TODO: support any custom naming scheme, e.g. flat, when there are
        // no directories for blocks
        var decl = this.getDeclByIntrospection(PATH.dirname(this.get('block', [blockName])));
        return decl.length? decl.shift() : {};
    },

    /**
     * Get declaration of level directory or one of its subdirectories.
     *
     * @param {String} [from]  Relative path to subdirectory of level directory to start introspection from.
     * @return {Array}  Array of declaration.
     */
    getDeclByIntrospection: function(from) {

        this._declIntrospector || (this._declIntrospector = this.createIntrospector({

            creator: function(res, match) {
                if (match && match.tech) {
                    return this._mergeMatchToDecl(match, res);
                }
                return res;
            }

        }));

        return this._declIntrospector(from);
    },

    /**
     * Get BEM entities from level directory or one of its subdirectories.
     *
     * @param {String} [from]  Relative path to subdirectory of level directory to start introspection from.
     * @return {Array}  Array of entities.
     */
    getItemsByIntrospection: function(from) {

        this._itemsIntrospector || (this._itemsIntrospector = this.createIntrospector());
        return this._itemsIntrospector(from);

    },

    scanFiles: function(force) {
        var list = {},
            blocks = {},
            flat = [],
            files = {
                files: list,
                tree: blocks,
                blocks: flat
            },
            items = {
                push: function(file, item) {
                    file.suffix = item.suffix[0] === '.'?item.suffix.substr(1):item.suffix;
                    (list[file.suffix] || (list[file.suffix] = [])).push(file);
                    flat.push(item);

                    var block = blocks[item.block] || (blocks[item.block] = {elems: {}, mods: {}, files: {}});
                    if (item.mod && !item.elem) {
                        block = block.mods[item.mod] || (block.mods[item.mod] = {vals: {}, files: {}});

                        if (item.val) block = block.vals[item.val] || (block.vals[item.val] = {files: {}});
                    }

                    if (item.elem) {
                        block = block.elems[item.elem] || (block.elems[item.elem] = {mods: {}, files: {}});

                        if (item.mod) block = block.mods[item.mod] || (block.mods[item.mod] = {vals: {}, files: {}});
                        if (item.val) block = block.vals[item.val] || (block.vals[item.val] = {files: {}});
                    }

                    (block.files[file.suffix] || (block.files[file.suffix] = [])).push(file);
                }
            };

        if (this.files && !force) return this.files;

        var _this = this,
            cachePath = PATH.join(this.projectRoot, '.bem', 'cache', PATH.relative(this.projectRoot, this.dir));

        if (this.cache) {
            try {
                _this.files = JSON.parse(FS.readFileSync(PATH.join(cachePath, 'files.json')));
                return _this.files;

            } catch(err) {
                LOGGER.fdebug('cache for level not found', _this.dir);
            }
        }

        _this.scan(items);
        _this.files = files;

        return bemUtil
            .mkdirp(cachePath)
            .then(function() {
                return bemUtil.writeFile(PATH.join(cachePath, 'files.json'), JSON.stringify(files));
            })
            .then(function() {
                return files;
            });
    },

    scan: function(items) {

        if (!bemUtil.isDirectory(this.dir)) return;

        LOGGER.time('scan ' + this.dir);

        var _this = this;

        this.suffixToTech = {};
        Object.keys(this.getTechs()).forEach(function(tech) {
            try {
                tech = this.getTech(tech);

                tech.getSuffixes().forEach(function(s) {
                    this.suffixToTech['.' + s] = tech.getTechName();
                }, this);
            } catch(err) {
                LOGGER.fwarn(err.message);
            }

        }, this);

        _this.scanBlocks(_this.dir, items);

        LOGGER.timeEndLevel('debug', 'scan ' + _this.dir);
    },

    scanBlocks: function(path, items) {
        var dirs = [],
            _this = this;

        bemUtil.getDirsFilesSync(path, dirs);

        return dirs
            .filter(function(dir) {
                dir = dir.file;
                return dir[0] !== '_' && dir[0] !== '.';
            })
            .forEach(function(block) {
                return _this.scanBlock(_this.dir, block.file, items);
            });
    },

    scanBlock: function(path, block, items) {
        var _this = this,
            dirs = [], files = [];

        bemUtil.getDirsFilesSync(PATH.join(path, block), dirs, files);

        var blockPart = block + '.',
            blockPartL = blockPart.length;

        files.forEach(function(f) {
            var file = f.file;
            if (file.substr(0, blockPartL) !== blockPart) return;

            var suffix = file.substr(blockPartL - 1);

            items.push(f, {
                block: block,
                suffix: suffix,
                tech: _this.suffixToTech[suffix]
            });
        });

        dirs.forEach(function(d) {
            var dir = d.file;
            if (_this.isElemDir(dir)) return _this.scanElem(path, block, dir, items);
            if (_this.isModDir(dir)) return _this.scanMod(path, block, null, dir, items);
            if (dir.substr(0, blockPartL) !== blockPart) return;

            var suffix = dir.substr(blockPartL - 1);

            items.push(d, {
                block: block,
                suffix: suffix,
                tech: _this.suffixToTech[suffix]
            });

            files = [];
            bemUtil.getDirsFilesSync(PATH.join(path, block, dir), files, files);

            files.forEach(function(file) {
                var suffix = (dir + PATH.dirSep + file.file).substr(blockPartL - 1);

                items.push(file, {
                    block: block,
                    suffix: suffix,
                    tech: _this.suffixToTech[suffix]
                });
            });
        });
    },

    isElemDir: function(dir) {
        return dir[0] === '_' && dir[1] === '_' && !~dir.indexOf('.');
    },

    blockElemFileSeparator: '__',
    elemDirPrefix: '__',

    scanElem: function(path, block, elem, items) {
        var _this = this,
            dir = path + PATH.dirSep + block + PATH.dirSep + elem,
            dirs = [], files = [];

        bemUtil.getDirsFilesSync(dir, dirs, files);

        var blockPart = block + _this.blockElemFileSeparator + elem.substr(_this.elemDirPrefix.length) + '.',
            blockPartL = blockPart.length,
            prefixLen = _this.elemDirPrefix.length;

        files.forEach(function(f) {
            var file = f.file;
            if (file.substr(0, blockPartL) !== blockPart) return;

            var suffix = file.substr(blockPartL - 1);

            items.push(f, {
                block: block,
                elem: elem.substr(prefixLen),
                suffix: suffix,
                tech: _this.suffixToTech[suffix]
            });
        });

        dirs.forEach(function(d) {
            if (_this.isModDir(d.file)) return _this.scanMod(path, block, elem, d.file, items);
            if (d.file.substr(0, blockPartL) !== blockPart) return;

            var suffix = d.file.substr(blockPartL - 1);

            items.push(d, {
                block: block,
                elem: elem.substr(prefixLen),
                suffix: suffix,
                tech: _this.suffixToTech[suffix]
            });

            files = [];

            bemUtil.getDirsFilesSync(PATH.join(dir, d.file), null, files);

            files.forEach(function(file) {
                var suffix = (d.file + PATH.dirSep + file.file).substr(blockPartL - 1);

                items.push(file, {
                    block: block,
                    elem: elem.substr(prefixLen),
                    suffix: suffix,
                    tech: _this.suffixToTech[suffix]
                });
            });
        });
    },

    isModDir: function(dir) {
        return dir[0] === '_' && dir[1] !== '_';
    },

    scanMod: function(path, block, elem, mod, items) {
        var _this = this,
            dir = path + PATH.dirSep + block + PATH.dirSep + (elem?elem+PATH.dirSep:'') + mod,
            dirs = [], files = [];

        bemUtil.getDirsFilesSync(dir, dirs, files);

        var blockPart = block  + (elem?_this.blockElemFileSeparator + elem.substr(_this.elemDirPrefix.length):'') + mod,
            blockPartL = blockPart.length;

        files.forEach(function(f) {
            var file = f.file;
            if (file.substr(0, blockPartL) !== blockPart) return;

            var val,
                modval = file.substr(blockPartL);

            if (modval[0] === '_') val = modval.substr(1);
            else if (modval[0] !== '.') return;

            var suffix = modval.substr(modval.indexOf('.')),
                item = {
                    block: block,
                    mod: mod.substr(1),
                    suffix: suffix,
                    tech: _this.suffixToTech[suffix]
                };

            if (elem) item.elem = elem.substr(_this.elemDirPrefix.length);
            if (val) item.val = val.substr(0, val.indexOf('.'));

            items.push(f, item);
        });

        dirs.forEach(function(d) {
            if (d.file.substr(0, blockPartL) !== blockPart) return;

            var val,
                modval = d.file.substr(blockPartL);

            if (modval[0] === '_') val = modval.substr(1);
            else if (modval[0] !== '.') return;

            var suffix = modval.substr(modval.indexOf('.')),
                item = {
                    block: block,
                    mod: mod.substr(1),
                    suffix: suffix,
                    tech: _this.suffixToTech[suffix]
                };

            if (elem) item.elem = elem.substr(_this.elemDirPrefix.length);
            if (val) item.val = val.substr(0, val.indexOf('.'));

            items.push(d, item);

            files = [];

            bemUtil.getDirsFilesSync(PATH.join(dir, d.file), null, files);

            files.forEach(function(file) {
                var suffix = modval.substr(modval.indexOf('.')) + PATH.dirSep + file.file,
                    item = {
                        block: block,
                        mod: mod.substr(1),
                        suffix: suffix,
                        tech: _this.suffixToTech[suffix]
                    };

                if (elem) item.elem = elem.substr(_this.elemDirPrefix.length);
                if (val) item.val = val.substr(0, val.indexOf('.'));

                items.push(file, item);
            });
        });
    },

    /**
     * Creates preconfigured introspection functions.
     *
     * @param {Object} [opts]  Introspector options.
     * @param {String} [opts.from]  Relative path to subdirectory of level directory to start introspection from.
     * @param {Function} [opts.init]  Function to return initial value of introspection.
     * @param {Function} [opts.filter]  Function to filter paths to introspect, must return {Boolean}.
     * @param {Function} [opts.matcher]  Function to perform match of paths, must return introspected value.
     * @param {Function} [opts.creator]  Function to modify introspection object with matched value, must return new introspection.
     * @return {Function}  Introspection function.
     */
    createIntrospector: function(opts) {

        var level = this;

        if (!opts) opts = {
            opts: false
        };

        // clone opts
        opts = bemUtil.extend({}, opts);

        // set default options
        opts.from || (opts.from = '.');

        // initial value initializer
        opts.init || (opts.init = function() {
            return [];
        });

        // paths filter function
        opts.filter || (opts.filter = function(path) {
            return !this.isIgnorablePath(path);
        });

        // matcher function
        opts.matcher || (opts.matcher = function(path) {
            return this.matchAny(path);
        });

        // result creator function
        opts.creator || (opts.creator = function(res, match) {
            if (match && match.tech) res.push(match);
            return res;
        });

        /**
         * Introspection function.
         *
         * @param {String} [from]  Relative path to subdirectory of level directory to start introspection from.
         * @param {*} [res]  Initial introspection value to extend.
         * @return {*}
         */
        return function(from, res) {

            if (opts.opts === false) {
                level.scanFiles();
                return level.files.blocks;
            }

            from = PATH.resolve(level.dir, from || opts.from);
            res || (res = opts.init.call(level));

            bemUtil.fsWalkTree(from, function(path) {
                    res = opts.creator.call(level, res, opts.matcher.call(level, path));
                },
                opts.filter,
                level);

            return res;

        };

    },

    _ignorePathRe: /\.(svn|git)$/,

    /**
     * Check path if it must be ignored during introspection.
     *
     * @param {String} path  Path to check.
     * @return {Boolean}  True if path must be ignored.
     */
    isIgnorablePath: function(path) {
        return this._ignorePathRe.test(path);
    },

    _mergeMatchToDecl: function(match, decl) {
        var blocks, elems, mods, vals,
            techAdded = false,
            addTech = function(o) {
                if(!techAdded && match.tech) {
                    o.techs = [{ name: match.tech }];
                    techAdded = true;
                }
                return o;
            };

        match.val &&
            (vals = [addTech({name: match.val})]);
        match.mod && match.val &&
            (mods = [addTech({name: match.mod, vals: vals})]);
        match.mod && !match.val &&
            (mods = [addTech({name: match.mod})]);
        match.elem &&
            (elems = [addTech({name: match.elem, mods: mods})]) &&
            (blocks = [addTech({name: match.block, elems: elems})]);
        !match.elem &&
            (blocks = [addTech({name: match.block, mods: mods})]);

        return bemUtil.mergeDecls(decl, blocks);
    }

});


text:
require 'zip'
require 'rubyXL/objects/relationships'
require 'rubyXL/objects/document_properties'
require 'rubyXL/objects/content_types'
require 'rubyXL/objects/workbook'

module RubyXL

  class WorkbookRoot
    @@debug = nil

    attr_accessor :filepath
    attr_accessor :thumbnail, :core_properties, :document_properties, :custom_properties, :workbook
    attr_accessor :content_types, :rels_hash

    include RubyXL::RelationshipSupport

    define_relationship(RubyXL::ThumbnailFile,          :thumbnail)
    define_relationship(RubyXL::CorePropertiesFile,     :core_properties)
    define_relationship(RubyXL::DocumentPropertiesFile, :document_properties)
    define_relationship(RubyXL::CustomPropertiesFile,   :custom_properties)
    define_relationship(RubyXL::Workbook,               :workbook)

    def related_objects
      [ content_types, thumbnail, core_properties, document_properties, custom_properties, workbook ]
    end

    def self.default
      obj = self.new
      obj.document_properties    = RubyXL::DocumentPropertiesFile.new
      obj.core_properties        = RubyXL::CorePropertiesFile.new
      obj.relationship_container = RubyXL::OOXMLRelationshipsFile.new
      obj.content_types          = RubyXL::ContentTypes.new
      obj
    end

    def stream
      stream = Zip::OutputStream.write_buffer { |zipstream|
        self.rels_hash = {}
        self.relationship_container.owner = self
        collect_related_objects.compact.each { |obj|
          puts "<-- DEBUG: adding relationship to #{obj.class}" if @@debug
          obj.root = self if obj.respond_to?(:root=)
          self.rels_hash[obj.class] ||= []
          self.rels_hash[obj.class] << obj
        }

        self.rels_hash.keys.sort_by{ |c| c::SAVE_ORDER }.each { |klass|
          puts "<-- DEBUG: saving related #{klass} files" if @@debug
          self.rels_hash[klass].each { |obj|
            puts "<-- DEBUG:   > #{obj.xlsx_path}" if @@debug
            obj.add_to_zip(zipstream)
          }
        }
      }
      stream.rewind
      stream
    end

    def xlsx_path
      OOXMLTopLevelObject::ROOT
    end

    def self.parse_file(xl_file_path, opts)
      begin
        ::Zip::File.open(xl_file_path) { |zip_file|
          root = self.new
          root.filepath = xl_file_path
          root.content_types = RubyXL::ContentTypes.parse_file(zip_file, ContentTypes::XLSX_PATH)
          root.load_relationships(zip_file, OOXMLTopLevelObject::ROOT)
          root.workbook.root = root
          root
        }
      rescue ::Zip::Error => e
        raise e, "XLSX file format error: #{e}", e.backtrace
      end
    end

  end

end

redpajama_set_name: RedPajamaGithub


text:
<?php defined( 'BASEPATH') OR exit( 'No direct script access allowed');

?>

<!DOCTYPE html>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>EuroZoneGlobal</title>

    <link href="<?php echo base_url("assets/vendors/bootstrap/dist/css/bootstrap.min.css");?>" rel="stylesheet">

    <link href="<?php echo base_url("assets/vendors/font-awesome/css/font-awesome.min.css");?>" rel="stylesheet">

    <link href="<?php echo base_url("assets/vendors/animate.css/animate.min.css");?>" rel="stylesheet">

    <link href="<?php echo base_url("assets/vendors/nprogress/nprogress.css");?>" rel="stylesheet">

    <link href="<?php echo base_url("assets/vendors/iCheck/skins/flat/green.css");?>" rel="stylesheet">

    <link href="<?php echo base_url("assets/vendors/bootstrap-progressbar/css/bootstrap-progressbar-3.3.4.min.css");?>" rel="stylesheet">

    <link href="<?php echo base_url("assets/vendors/jqvmap/dist/jqvmap.min.css");?>" rel="stylesheet"/>

    <link href="<?php echo base_url("assets/build/css/custom.min.css");?>" rel="stylesheet">

    <link rel="shortcut icon" href="<?php echo base_url("assets/ico/euro-xxl.png"); ?>">
    <link rel="apple-touch-icon-precomposed" sizes="144x144" href="<?php echo base_url("assets/ico/euro-xxl.png"); ?>">
    <link rel="apple-touch-icon-precomposed" sizes="114x114" href="<?php echo base_url("assets/ico/euro-xxl.png"); ?>">
    <link rel="apple-touch-icon-precomposed" sizes="72x72" href="<?php echo base_url("assets/ico/euro-xxl.png"); ?>">
    <link rel="apple-touch-icon-precomposed" href="<?php echo base_url("assets/ico/euro-xxl.png"); ?>">

    <link href="<?php echo base_url("assets/vendors/datatables.net-bs/css/dataTables.bootstrap.min.css");?>" rel="stylesheet">
    <link href="<?php echo base_url("assets/vendors/datatables.net-buttons-bs/css/buttons.bootstrap.min.css");?>" rel="stylesheet">
    <link href="<?php echo base_url("assets/vendors/datatables.net-fixedheader-bs/css/fixedHeader.bootstrap.min.css");?>" rel="stylesheet">
    <link href="<?php echo base_url("assets/vendors/datatables.net-responsive-bs/css/responsive.bootstrap.min.css");?>" rel="stylesheet">
    <link href="<?php echo base_url("assets/vendors/datatables.net-scroller-bs/css/scroller.bootstrap.min.css");?>" rel="stylesheet">

    <link rel="stylesheet" type="text/css" href="//cdn.datatables.net/1.10.12/css/jquery.dataTables.css">

              <a href="<?php echo base_url('dashboard');?>" class="site_title">

              EuroZoneGlobal

                <img src="<?php echo base_url("assets/images/photo.jpg");?>" alt="..." class="img-circle profile_img">

                Welcome,

<?php //echo $uname; ?>

<?php echo $uname; ?>

 Home

<a href="<?php echo base_url('dashboard');?>">Dashboard

                  <?php if ($role==1 || $role==3) { ?>

 Network & Bonus

<a href="<?php echo base_url("reg_downline");?>">Register Downline

<a href="<?php echo base_url("downline");?>">Downline List

<a href="<?php echo base_url("bonus");?>">Bonus List

                  <?php } ?>

                  <?php //if ($role==2 || $role==3) { ?>

Wallet

<a href="<?php echo base_url("wallet");?>">Wallet Transfer

<a href="<?php echo base_url("cash");?>">Cash Transaction

<a href="<?php echo base_url("register");?>">Register Transaction

                  <?php //} ?>

 Profile

<a href="<?php echo base_url("profile");?>">View Profile

<a href="<?php echo base_url("change_pass");?>">Change Password

<a href="<?php echo base_url("login_new/logout");?>">Logout

                  <?php if ($role==1) { ?>

Admin

<a href="<?php echo base_url("manage/user");?>">Manage User

<a href="<?php echo base_url("manage/passwd");?>">Reset Password

<a href="<?php echo base_url("manage");?>">Setting

                  <?php } ?>

              <a data-toggle="tooltip" data-placement="top" title="Logout" href="<?php echo base_url("login_new/logout"); ?>">


text:
import { useCallback, useEffect, useState } from 'react';
import classnames from 'classnames';
import { IConstraint } from 'interfaces/strategy';
import { useStyles } from '../ConstraintAccordion.styles';
import { ConstraintAccordionEditBody } from './ConstraintAccordionEditBody/ConstraintAccordionEditBody';
import { ConstraintAccordionEditHeader } from './ConstraintAccordionEditHeader/ConstraintAccordionEditHeader';
import { Accordion, AccordionDetails, AccordionSummary } from '@mui/material';
import { cleanConstraint } from 'utils/cleanConstraint';
import useFeatureApi from 'hooks/api/actions/useFeatureApi/useFeatureApi';
import useUnleashContext from 'hooks/api/getters/useUnleashContext/useUnleashContext';
import { formatUnknownError } from 'utils/formatUnknownError';
import { IUnleashContextDefinition } from 'interfaces/context';
import { useConstraintInput } from './ConstraintAccordionEditBody/useConstraintInput/useConstraintInput';
import { Operator } from 'constants/operators';
import { ResolveInput } from './ConstraintAccordionEditBody/ResolveInput/ResolveInput';

interface IConstraintAccordionEditProps {
    constraint: IConstraint;
    onCancel: () => void;
    onSave: (constraint: IConstraint) => void;
    compact: boolean;
    onDelete?: () => void;
}

export const CANCEL = 'cancel';
export const SAVE = 'save';

const resolveContextDefinition = (
    context: IUnleashContextDefinition[],
    contextName: string
): IUnleashContextDefinition => {
    const definition = context.find(
        contextDef => contextDef.name === contextName
    );

    return (
        definition || {
            name: '',
            description: '',
            createdAt: '',
            sortOrder: 1,
            stickiness: false,
        }
    );
};

export const ConstraintAccordionEdit = ({
    constraint,
    compact,
    onCancel,
    onSave,
    onDelete,
}: IConstraintAccordionEditProps) => {
    const [localConstraint, setLocalConstraint] = useState<IConstraint>(
        cleanConstraint(constraint)
    );

    const { context } = useUnleashContext();
    const [contextDefinition, setContextDefinition] = useState(
        resolveContextDefinition(context, localConstraint.contextName)
    );
    const { validateConstraint } = useFeatureApi();
    const [expanded, setExpanded] = useState(false);
    const [action, setAction] = useState('');
    const { classes: styles } = useStyles();

    useEffect(() => {
        // Setting expanded to true on mount will cause the accordion
        // animation to take effect and transition the expanded accordion in
        setExpanded(true);
    }, []);

    useEffect(() => {
        setContextDefinition(
            resolveContextDefinition(context, localConstraint.contextName)
        );
    }, [localConstraint.contextName, context]);

    const setContextName = useCallback((contextName: string) => {
        setLocalConstraint(prev => ({
            ...prev,
            contextName,
            values: [],
            value: '',
        }));
    }, []);

    const setOperator = useCallback((operator: Operator) => {
        setLocalConstraint(prev => ({
            ...prev,
            operator,
            values: [],
            value: '',
        }));
    }, []);

    const setValues = useCallback((values: string[]) => {
        setLocalConstraint(prev => ({
            ...prev,
            values,
        }));
    }, []);

    const setValue = useCallback((value: string) => {
        setLocalConstraint(prev => ({ ...prev, value }));
    }, []);

    const setInvertedOperator = () => {
        setLocalConstraint(prev => ({ ...prev, inverted: !prev.inverted }));
    };

    const setCaseInsensitive = useCallback(() => {
        setLocalConstraint(prev => ({
            ...prev,
            caseInsensitive: !prev.caseInsensitive,
        }));
    }, []);

    const removeValue = useCallback(
        (index: number) => {
            const valueCopy = [...localConstraint.values!];
            valueCopy.splice(index, 1);

            setValues(valueCopy);
        },
        [localConstraint, setValues]
    );

    const triggerTransition = () => {
        setExpanded(false);
    };

    const validateConstraintValues = () => {
        const hasValues =
            Array.isArray(localConstraint.values) &&
            Boolean(localConstraint.values.length > 0);
        const hasValue = Boolean(localConstraint.value);

        if (hasValues || hasValue) {
            setError('');
            return true;
        }
        setError('You must provide a value for the constraint');
        return false;
    };

    const onSubmit = async () => {
        const hasValues = validateConstraintValues();
        if (!hasValues) return;
        const [typeValidatorResult, err] = validator();

        if (!typeValidatorResult) {
            setError(err);
        }

        if (typeValidatorResult) {
            try {
                await validateConstraint(localConstraint);
                setError('');
                setAction(SAVE);
                triggerTransition();
                return;
            } catch (error: unknown) {
                setError(formatUnknownError(error));
            }
        }
    };

    const { input, validator, setError, error } = useConstraintInput({
        contextDefinition,
        localConstraint,
    });

    useEffect(() => {
        setError('');
        setLocalConstraint(localConstraint => cleanConstraint(localConstraint));
    }, [localConstraint.operator, localConstraint.contextName, setError]);

    return (
        <div className={styles.form}>
            <Accordion
                className={classnames(styles.accordion, styles.accordionEdit)}
                classes={{
                    expanded: styles.accordionRoot,
                }}
                style={{ boxShadow: 'none' }}
                expanded={expanded}
                TransitionProps={{
                    onExited: () => {
                        if (action === CANCEL) {
                            setAction('');
                            onCancel();
                        } else if (action === SAVE) {
                            setAction('');
                            onSave(localConstraint);
                        }
                    },
                }}
            >
                <AccordionSummary className={styles.summary}>
                    <ConstraintAccordionEditHeader
                        localConstraint={localConstraint}
                        setLocalConstraint={setLocalConstraint}
                        setContextName={setContextName}
                        setOperator={setOperator}
                        action={action}
                        compact={compact}
                        setInvertedOperator={setInvertedOperator}
                        setCaseInsensitive={setCaseInsensitive}
                        onDelete={onDelete}
                    />
                </AccordionSummary>

                <AccordionDetails
                    className={styles.accordionDetails}
                    style={{ padding: 0 }}
                >
                    <ConstraintAccordionEditBody
                        localConstraint={localConstraint}
                        setValues={setValues}
                        setValue={setValue}
                        triggerTransition={triggerTransition}
                        setAction={setAction}
                        onSubmit={onSubmit}
                    >
                        <ResolveInput
                            setValues={setValues}
                            setValue={setValue}
                            setError={setError}
                            localConstraint={localConstraint}
                            input={input}
                            error={error}
                            contextDefinition={contextDefinition}
                            removeValue={removeValue}
                        />
                    </ConstraintAccordionEditBody>
                </AccordionDetails>
            </Accordion>
        </div>
    );
};


text:
package org.unitime.timetable.test;

import java.util.Date;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cpsolver.coursett.model.Lecture;
import org.cpsolver.coursett.model.Placement;
import org.cpsolver.coursett.model.RoomLocation;
import org.cpsolver.coursett.model.TimeLocation;
import org.cpsolver.studentsct.StudentSectioningLoader;
import org.cpsolver.studentsct.StudentSectioningModel;
import org.cpsolver.studentsct.Test;
import org.cpsolver.studentsct.model.AcademicAreaCode;
import org.cpsolver.studentsct.model.Config;
import org.cpsolver.studentsct.model.Course;
import org.cpsolver.studentsct.model.CourseRequest;
import org.cpsolver.studentsct.model.Enrollment;
import org.cpsolver.studentsct.model.FreeTimeRequest;
import org.cpsolver.studentsct.model.Offering;
import org.cpsolver.studentsct.model.Request;
import org.cpsolver.studentsct.model.Section;
import org.cpsolver.studentsct.model.Student;
import org.cpsolver.studentsct.model.Subpart;
import org.hibernate.Transaction;
import org.unitime.timetable.model.AcademicAreaClassification;
import org.unitime.timetable.model.Assignment;
import org.unitime.timetable.model.ClassInstructor;
import org.unitime.timetable.model.ClassWaitList;
import org.unitime.timetable.model.Class_;
import org.unitime.timetable.model.CourseDemand;
import org.unitime.timetable.model.CourseOffering;
import org.unitime.timetable.model.DatePattern;
import org.unitime.timetable.model.ExactTimeMins;
import org.unitime.timetable.model.InstrOfferingConfig;
import org.unitime.timetable.model.InstructionalOffering;
import org.unitime.timetable.model.LastLikeCourseDemand;
import org.unitime.timetable.model.Location;
import org.unitime.timetable.model.PosMajor;
import org.unitime.timetable.model.PosMinor;
import org.unitime.timetable.model.PreferenceLevel;
import org.unitime.timetable.model.Room;
import org.unitime.timetable.model.RoomPref;
import org.unitime.timetable.model.SchedulingSubpart;
import org.unitime.timetable.model.Session;
import org.unitime.timetable.model.StudentClassEnrollment;
import org.unitime.timetable.model.TimePatternModel;
import org.unitime.timetable.model.TimePref;
import org.unitime.timetable.model.comparators.SchedulingSubpartComparator;
import org.unitime.timetable.model.dao.SessionDAO;
import org.unitime.timetable.util.Formats;
import org.unitime.timetable.util.duration.DurationModel;

/**
 * @author Tomas Muller
 */
public class BatchStudentSectioningLoader extends StudentSectioningLoader {
    private static Log sLog = LogFactory.getLog(BatchStudentSectioningLoader.class);
    private boolean iIncludeCourseDemands = true;
    private boolean iIncludeLastLikeStudents = true;
    private boolean iIncludeUseCommittedAssignments = false;
    private boolean iMakeupAssignmentsFromRequiredPrefs = false;
    private boolean iLoadStudentInfo = false;
    private String iInitiative = null;
    private String iTerm = null;
    private String iYear = null;
    private long iMakeupAssignmentId = 0;

    public BatchStudentSectioningLoader(StudentSectioningModel model, org.cpsolver.ifs.assignment.Assignment<Request, Enrollment> assignment) {
        super(model, assignment);
        iIncludeCourseDemands = model.getProperties().getPropertyBoolean("Load.IncludeCourseDemands", iIncludeCourseDemands);
        iIncludeLastLikeStudents = model.getProperties().getPropertyBoolean("Load.IncludeLastLikeStudents", iIncludeLastLikeStudents);
        iIncludeUseCommittedAssignments = model.getProperties().getPropertyBoolean("Load.IncludeUseCommittedAssignments", iIncludeUseCommittedAssignments);
        iLoadStudentInfo = model.getProperties().getPropertyBoolean("Load.LoadStudentInfo", iLoadStudentInfo);
        iMakeupAssignmentsFromRequiredPrefs = model.getProperties().getPropertyBoolean("Load.MakeupAssignmentsFromRequiredPrefs", iMakeupAssignmentsFromRequiredPrefs);
        iInitiative = model.getProperties().getProperty("Data.Initiative");
        iYear = model.getProperties().getProperty("Data.Year");
        iTerm = model.getProperties().getProperty("Data.Term");
    }

    public void load() throws Exception {
        Session session = Session.getSessionUsingInitiativeYearTerm(iInitiative, iYear, iTerm);

        if (session==null) throw new Exception("Session "+iInitiative+" "+iTerm+iYear+" not found!");

        sLog.info("Loading data for "+iInitiative+" "+iTerm+iYear+"...");

        load(session);
    }

    private String getInstructorIds(Class_ clazz) {
        if (!clazz.isDisplayInstructor().booleanValue()) return null;
        String ret = null;
        TreeSet ts = new TreeSet(clazz.getClassInstructors());
        for (Iterator i=ts.iterator();i.hasNext();) {
            ClassInstructor ci = (ClassInstructor)i.next();
            if (!ci.isLead().booleanValue()) continue;
            if (ret==null)
                ret = ci.getInstructor().getUniqueId().toString();
            else
                ret += ":"+ci.getInstructor().getUniqueId().toString();
        }
        return ret;
    }

    private String getInstructorNames(Class_ clazz) {
        if (!clazz.isDisplayInstructor().booleanValue()) return null;
        String ret = null;
        TreeSet ts = new TreeSet(clazz.getClassInstructors());
        for (Iterator i=ts.iterator();i.hasNext();) {
            ClassInstructor ci = (ClassInstructor)i.next();
            if (!ci.isLead().booleanValue()) continue;
            if (ret==null)
                ret = ci.getInstructor().nameShort();
            else
                ret += ":"+ci.getInstructor().nameShort();
        }
        return ret;
    }

    public TimeLocation makeupTime(Class_ c) {
        DatePattern datePattern = c.effectiveDatePattern();
        if (datePattern==null) {
            sLog.warn("        -- makup time for "+c.getClassLabel()+": no date pattern set");
            return null;
        }
        for (Iterator i=c.getEffectiveTimePreferences().iterator();i.hasNext();) {
            TimePref tp = (TimePref)i.next();
            TimePatternModel pattern = tp.getTimePatternModel();
            if (pattern.isExactTime()) {
    			DurationModel dm = c.getSchedulingSubpart().getInstrOfferingConfig().getDurationModel();
    			int minsPerMeeting = dm.getExactTimeMinutesPerMeeting(c.getSchedulingSubpart().getMinutesPerWk(), c.effectiveDatePattern(), pattern.getExactDays());
                int length = ExactTimeMins.getNrSlotsPerMtg(minsPerMeeting);
                int breakTime = ExactTimeMins.getBreakTime(minsPerMeeting);
                return new TimeLocation(pattern.getExactDays(),pattern.getExactStartSlot(),length,PreferenceLevel.sIntLevelNeutral,0,datePattern.getUniqueId(),datePattern.getName(),datePattern.getPatternBitSet(),breakTime);
            } else {
                for (int time=0;time<pattern.getNrTimes(); time++) {
                    for (int day=0;day<pattern.getNrDays(); day++) {
                        String pref = pattern.getPreference(day,time);
                        if (pref.equals(PreferenceLevel.sRequired)) {
                        return new TimeLocation(
                                pattern.getDayCode(day),
                                pattern.getStartSlot(time),
                                pattern.getSlotsPerMtg(),
                                PreferenceLevel.prolog2int(pattern.getPreference(day, time)),
                                pattern.getNormalizedPreference(day,time,0.77),
                                datePattern.getUniqueId(),
                                datePattern.getName(),
                                datePattern.getPatternBitSet(),
                                pattern.getBreakTime());
                        }
                    }
                }
            }
        }
        if (c.getEffectiveTimePreferences().isEmpty())
            sLog.warn("        -- makup time for "+c.getClassLabel()+": no time preference set");
        else
            sLog.warn("        -- makup time for "+c.getClassLabel()+": no required time set");
        return null;
    }

    public Vector makeupRooms(Class_ c) {
        Vector rooms = new Vector();
        for (Iterator i=c.getEffectiveRoomPreferences().iterator();i.hasNext();) {
            RoomPref rp = (RoomPref)i.next();
            if (!PreferenceLevel.sRequired.equals(rp.getPrefLevel().getPrefProlog())) {
                sLog.warn("        -- makup room for "+c.getClassLabel()+": preference for "+rp.getRoom().getLabel()+" is not required");
                continue;
            }
            Location room = (Location)rp.getRoom();
            RoomLocation roomLocation = new RoomLocation(
                    room.getUniqueId(),
                    room.getLabel(),
                    (room instanceof Room? ((Room)room).getBuilding().getUniqueId() : null),
                    0,
                    room.getCapacity().intValue(),
                    room.getCoordinateX(),
                    room.getCoordinateY(),
                    room.isIgnoreTooFar().booleanValue(),
                    null);
            rooms.addElement(roomLocation);
        }
        return rooms;
    }

    public Placement makeupPlacement(Class_ c) {
        TimeLocation time = makeupTime(c);
        if (time==null) return null;
        Vector rooms = makeupRooms(c);
        Vector times = new Vector(1); times.addElement(time);
        Lecture lecture = new Lecture(c.getUniqueId(), null, c.getSchedulingSubpart().getUniqueId(), c.getClassLabel(), times, rooms, rooms.size(), new Placement(null,time,rooms), 0, 0, 1.0);
        lecture.setNote(c.getNotes());
        Placement p = (Placement)lecture.getInitialAssignment();
        p.setAssignmentId(new Long(iMakeupAssignmentId++));
        lecture.setBestAssignment(p, 0l);
        sLog.debug("        -- makup placement for "+c.getClassLabel()+": "+p.getLongName(true));
        return p;
    }

    private Section loadSection(Subpart subpart, Section parentSection, Class_ c, int limit) {
        Placement p = null;
        if (iMakeupAssignmentsFromRequiredPrefs) {
            p = makeupPlacement(c);
        } else {
            Assignment a = c.getCommittedAssignment();
            p = (a==null?null:a.getPlacement());
        }
        Section section = new Section(c.getUniqueId().longValue(), limit, c.getClassLabel(), subpart, p, getInstructorIds(c), getInstructorNames(c), parentSection);
        if (section.getTime()!=null && section.getTime().getDatePatternId().equals(c.getSession().getDefaultDatePattern().getUniqueId()))
            section.getTime().setDatePattern(section.getTime().getDatePatternId(),"",section.getTime().getWeekCode());
        if (section.getTime()!=null && section.getTime().getDatePatternName().startsWith("generated")) {
        	Formats.Format<Date> sdf = Formats.getDateFormat(Formats.Pattern.DATE_EVENT_SHORT);
            section.getTime().setDatePattern(
                    section.getTime().getDatePatternId(),
                    sdf.format(c.effectiveDatePattern().getStartDate())+" - "+sdf.format(c.effectiveDatePattern().getEndDate()),
                    section.getTime().getWeekCode());
        }
        return section;
    }

    private Offering loadOffering(InstructionalOffering io, Hashtable courseTable, Hashtable classTable) {
        sLog.debug("Loading offering "+io.getCourseName());
        if (!io.hasClasses()) {
            sLog.debug("  -- offering "+io.getCourseName()+" has no class");
            return null;
        }
        Offering offering = new Offering(io.getUniqueId().longValue(), io.getCourseName());
        boolean unlimited = false;
        for (Iterator i=io.getInstrOfferingConfigs().iterator();i.hasNext();) {
            InstrOfferingConfig ioc = (InstrOfferingConfig)i.next();
            if (ioc.isUnlimitedEnrollment().booleanValue()) unlimited = true;
        }
        for (Iterator i=io.getCourseOfferings().iterator();i.hasNext();) {
            CourseOffering co = (CourseOffering)i.next();
            int projected = (co.getProjectedDemand()==null?0:co.getProjectedDemand().intValue());
            int limit = co.getInstructionalOffering().getLimit().intValue();
            if (unlimited) limit=-1;
            if (co.getReservation() != null)
            	limit = co.getReservation();
            Course course = new Course(co.getUniqueId().longValue(), co.getSubjectAreaAbbv(), co.getCourseNbr(), offering, limit, projected);
            courseTable.put(co.getUniqueId(), course);
            sLog.debug("  -- created course "+course);
        }
        Hashtable class2section = new Hashtable();
        Hashtable ss2subpart = new Hashtable();
        for (Iterator i=io.getInstrOfferingConfigs().iterator();i.hasNext();) {
            InstrOfferingConfig ioc = (InstrOfferingConfig)i.next();
            if (!ioc.hasClasses()) {
                sLog.debug("  -- config "+ioc.getName()+" has no class");
                continue;
            }
            Config config = new Config(ioc.getUniqueId().longValue(), (ioc.isUnlimitedEnrollment() ? -1 : ioc.getLimit()), ioc.getCourseName()+" ["+ioc.getName()+"]", offering);
            sLog.debug("  -- created config "+config);
            TreeSet subparts = new TreeSet(new SchedulingSubpartComparator());
            subparts.addAll(ioc.getSchedulingSubparts());
            for (Iterator j=subparts.iterator();j.hasNext();) {
                SchedulingSubpart ss = (SchedulingSubpart)j.next();
                String sufix = ss.getSchedulingSubpartSuffix();
                Subpart parentSubpart = (ss.getParentSubpart()==null?null:(Subpart)ss2subpart.get(ss.getParentSubpart()));
                if (ss.getParentSubpart()!=null && parentSubpart==null) {
                    sLog.error("    -- subpart "+ss.getSchedulingSubpartLabel()+" has parent "+ss.getParentSubpart().getSchedulingSubpartLabel()+", but the appropriate parent subpart is not loaded.");
                }
                Subpart subpart = new Subpart(ss.getUniqueId().longValue(), ss.getItype().getItype().toString()+sufix, ss.getItypeDesc().trim()+(sufix==null || sufix.length()==0?"":" ("+sufix+")"), config, parentSubpart);
                subpart.setAllowOverlap(ss.isStudentAllowOverlap());
                ss2subpart.put(ss, subpart);
                sLog.debug("    -- created subpart "+subpart);
                for (Iterator k=ss.getClasses().iterator();k.hasNext();) {
                    Class_ c = (Class_)k.next();
                    int limit = c.getClassLimit();
                    if (ioc.isUnlimitedEnrollment().booleanValue()) limit = -1;
                    if (!c.isEnabledForStudentScheduling()) limit = 0;
                    Section parentSection = (c.getParentClass()==null?null:(Section)class2section.get(c.getParentClass()));
                    if (c.getParentClass()!=null && parentSection==null) {
                        sLog.error("    -- class "+c.getClassLabel()+" has parent "+c.getParentClass().getClassLabel()+", but the appropriate parent section is not loaded.");
                    }
                    Section section = loadSection(subpart, parentSection, c, limit);
                    class2section.put(c, section);
                    classTable.put(c.getUniqueId(), section);
                    sLog.debug("      -- created section "+section);
                }
            }
        }
        return offering;
    }

    public Student loadStudent(org.unitime.timetable.model.Student s, Hashtable courseTable, Hashtable classTable) {
        sLog.debug("Loading student "+s.getUniqueId()+" (id="+s.getExternalUniqueId()+", name="+s.getFirstName()+" "+s.getMiddleName()+" "+s.getLastName()+")");
        Student student = new Student(s.getUniqueId().longValue());
        if (iLoadStudentInfo) loadStudentInfo(student,s);
        int priority = 0;
        for (Iterator i=new TreeSet(s.getCourseDemands()).iterator();i.hasNext();) {
            CourseDemand cd = (CourseDemand)i.next();
            if (cd.getFreeTime()!=null) {
                Request request = new FreeTimeRequest(
                        cd.getUniqueId().longValue(),
                        priority++,
                        cd.isAlternative().booleanValue(),
                        student,
                        new TimeLocation(
                                cd.getFreeTime().getDayCode().intValue(),
                                cd.getFreeTime().getStartSlot().intValue(),
                                cd.getFreeTime().getLength().intValue(),
                                0, 0,
                                s.getSession().getDefaultDatePattern().getUniqueId(),
                                "",
                                s.getSession().getDefaultDatePattern().getPatternBitSet(),
                                0)
                        );
                sLog.debug("  -- added request "+request);
            } else if (!cd.getCourseRequests().isEmpty()) {
                Vector courses = new Vector();
                HashSet selChoices = new HashSet();
                HashSet wlChoices = new HashSet();
                HashSet assignedSections = new HashSet();
                Config assignedConfig = null;
                for (Iterator j=new TreeSet(cd.getCourseRequests()).iterator();j.hasNext();) {
                    org.unitime.timetable.model.CourseRequest cr = (org.unitime.timetable.model.CourseRequest)j.next();
                    Course course = (Course)courseTable.get(cr.getCourseOffering().getUniqueId());
                    if (course==null) {
                        sLog.warn("  -- course "+cr.getCourseOffering().getCourseName()+" not loaded");
                        continue;
                    }
                    for (Iterator k=cr.getClassWaitLists().iterator();k.hasNext();) {
                        ClassWaitList cwl = (ClassWaitList)k.next();
                        Section section = course.getOffering().getSection(cwl.getClazz().getUniqueId().longValue());
                        if (section!=null) {
                            if (cwl.getType().equals(ClassWaitList.TYPE_SELECTION))
                                selChoices.add(section.getChoice());
                            else if (cwl.getType().equals(ClassWaitList.TYPE_WAITLIST))
                                wlChoices.add(section.getChoice());
                        }
                    }
                    if (assignedConfig==null) {
                        for (Iterator k=cr.getClassEnrollments().iterator();k.hasNext();) {
                            StudentClassEnrollment sce = (StudentClassEnrollment)k.next();
                            Section section = course.getOffering().getSection(sce.getClazz().getUniqueId().longValue());
                            if (section!=null) {
                                assignedSections.add(section);
                                assignedConfig = section.getSubpart().getConfig();
                            }
                        }
                    }
                    courses.addElement(course);
                }
                if (courses.isEmpty()) continue;
                CourseRequest request = new CourseRequest(
                        cd.getUniqueId().longValue(),
                        priority++,
                        cd.isAlternative().booleanValue(),
                        student,
                        courses,
                        cd.isWaitlist().booleanValue(),
                        cd.getTimestamp().getTime());
                request.getSelectedChoices().addAll(selChoices);
                request.getWaitlistedChoices().addAll(wlChoices);
                if (assignedConfig!=null && assignedSections.size()==assignedConfig.getSubparts().size()) {
                    Enrollment enrollment = new Enrollment(request, 0, assignedConfig, assignedSections, getAssignment());
                    request.setInitialAssignment(enrollment);
                }
                sLog.debug("  -- added request "+request);
            } else {
                sLog.warn("  -- course demand "+cd.getUniqueId()+" has no course requests");
            }
        }

        return student;
    }

    private void fixWeights() {
        Hashtable lastLike = new Hashtable();
        Hashtable real = new Hashtable();
        for (Student student: getModel().getStudents()) {
            for (Request request: student.getRequests()) {
                if (request instanceof CourseRequest) {
                    CourseRequest courseRequest = (CourseRequest)request;
                    Course course = (Course)courseRequest.getCourses().get(0);
                    Integer cnt = (Integer)(student.isDummy()?lastLike:real).get(course);
                    (student.isDummy()?lastLike:real).put(course, new Integer((cnt==null?0:cnt.intValue())+1));
                }
            }
        }
        for (Enumeration e=new Vector(getModel().getStudents()).elements();e.hasMoreElements();) {
            Student student = (Student)e.nextElement();
            for (Enumeration f=new Vector(student.getRequests()).elements();f.hasMoreElements();) {
                Request request = (Request)f.nextElement();
                if (!student.isDummy()) {
                    request.setWeight(1.0); continue;
                }
                if (request instanceof CourseRequest) {
                    CourseRequest courseRequest = (CourseRequest)request;
                    Course course = (Course)courseRequest.getCourses().get(0);
                    Integer lastLikeCnt = (Integer)lastLike.get(course);
                    Integer realCnt = (Integer)real.get(course);
                    courseRequest.setWeight(Test.getLastLikeStudentWeight(course, realCnt==null?0:realCnt.intValue(), lastLikeCnt==null?0:lastLikeCnt.intValue()));
                } else request.setWeight(1.0);
                 if (request.getWeight()<=0.0) {
                    getModel().removeVariable(request);
                    student.getRequests().remove(request);
                }
            }
            if (student.getRequests().isEmpty()) {
                getModel().getStudents().remove(student);
            }
        }
    }

    public void loadLastLikeStudent(org.hibernate.Session hibSession, LastLikeCourseDemand d, org.unitime.timetable.model.Student s, Long courseOfferingId, Hashtable studentTable, Hashtable courseTable, Hashtable classTable, Hashtable classAssignments) {
        sLog.debug("Loading last like demand of student "+s.getUniqueId()+" (id="+s.getExternalUniqueId()+", name="+s.getFirstName()+" "+s.getMiddleName()+" "+s.getLastName()+") for "+courseOfferingId);
        Student student = (Student)studentTable.get(s.getUniqueId());
        if (student==null) {
            student = new Student(s.getUniqueId().longValue(),true);
            if (iLoadStudentInfo) loadStudentInfo(student,s);
            studentTable.put(s.getUniqueId(),student);
        }
        int priority = student.getRequests().size();
        Vector courses = new Vector();
        Course course = (Course)courseTable.get(courseOfferingId);
        if (course==null) {
            sLog.warn("  -- course "+courseOfferingId+" not loaded");
            return;
        }
        courses.addElement(course);
        CourseRequest request = new CourseRequest(
                d.getUniqueId().longValue(),
                priority++,
                false,
                student,
                courses,
                false,
                null);
        sLog.debug("  -- added request "+request);
        if (classAssignments!=null && !classAssignments.isEmpty()) {
            HashSet assignedSections = new HashSet();
            HashSet classIds = (HashSet)classAssignments.get(s.getUniqueId());
            if (classIds!=null)
                for (Iterator i=classIds.iterator();i.hasNext();) {
                    Long classId = (Long)i.next();
                    Section section = (Section)request.getSection(classId.longValue());
                    if (section!=null) assignedSections.add(section);
                }
            if (!assignedSections.isEmpty()) {
                sLog.debug("    -- committed assignment: "+assignedSections);
                for (Enrollment enrollment: request.values(getAssignment())) {
                    if (enrollment.getAssignments().containsAll(assignedSections)) {
                        request.setInitialAssignment(enrollment);
                        sLog.debug("      -- found: "+enrollment);
                        break;
                    }
                }
            }
        }
    }

    public void loadStudentInfo(Student student, org.unitime.timetable.model.Student s) {
        HashSet majors = new HashSet();
        HashSet minors = new HashSet();
        for (Iterator i=s.getAcademicAreaClassifications().iterator();i.hasNext();) {
            AcademicAreaClassification aac = (AcademicAreaClassification)i.next();
            student.getAcademicAreaClasiffications().add(
                    new AcademicAreaCode(aac.getAcademicArea().getAcademicAreaAbbreviation(),aac.getAcademicClassification().getCode()));
            sLog.debug("  -- aac: "+aac.getAcademicArea().getAcademicAreaAbbreviation()+":"+aac.getAcademicClassification().getCode());
            for (Iterator j=aac.getAcademicArea().getPosMajors().iterator();j.hasNext();) {
                PosMajor major = (PosMajor)j.next();
                if (s.getPosMajors().contains(major)) {
                    student.getMajors().add(
                            new AcademicAreaCode(aac.getAcademicArea().getAcademicAreaAbbreviation(),major.getCode()));
                    majors.add(major);
                    sLog.debug("  -- mj: "+aac.getAcademicArea().getAcademicAreaAbbreviation()+":"+major.getCode());
                }

            }
            for (Iterator j=aac.getAcademicArea().getPosMinors().iterator();j.hasNext();) {
                PosMinor minor = (PosMinor)j.next();
                if (s.getPosMinors().contains(minor)) {
                    student.getMinors().add(
                            new AcademicAreaCode(aac.getAcademicArea().getAcademicAreaAbbreviation(),minor.getCode()));
                    minors.add(minor);
                    sLog.debug("  -- mn: "+aac.getAcademicArea().getAcademicAreaAbbreviation()+":"+minor.getCode());
                }

            }
        }
        for (Iterator i=s.getPosMajors().iterator();i.hasNext();) {
            PosMajor major = (PosMajor)i.next();
            if (!majors.contains(major)) {
                student.getMajors().add(new AcademicAreaCode(null,major.getCode()));
                sLog.debug("  -- mj: "+major.getCode());
            }
        }
        for (Iterator i=s.getPosMinors().iterator();i.hasNext();) {
            PosMinor minor = (PosMinor)i.next();
            if (!minors.contains(minor)) {
                student.getMajors().add(new AcademicAreaCode(null,minor.getCode()));
                sLog.debug("  -- mj: "+minor.getCode());
            }
        }
    }

    public void load(Session session) {
        org.hibernate.Session hibSession = new SessionDAO().getSession();
        Transaction tx = hibSession.beginTransaction();

        try {

            Hashtable courseTable = new Hashtable();
            Hashtable classTable = new Hashtable();
            List offerings = hibSession.createQuery(
                    "select distinct io from InstructionalOffering io " +
                    "left join fetch io.courseOfferings as co "+
                    "left join fetch io.instrOfferingConfigs as ioc "+
                    "left join fetch ioc.schedulingSubparts as ss "+
                    "left join fetch ss.classes as c "+
                    "where " +
                    "io.session.uniqueId=:sessionId and io.notOffered=false").
                    setLong("sessionId",session.getUniqueId().longValue()).
                    setFetchSize(1000).list();
            for (Iterator i=offerings.iterator();i.hasNext();) {
                InstructionalOffering io = (InstructionalOffering)i.next();
                Offering offering = loadOffering(io, courseTable, classTable);
                if (offering!=null) getModel().addOffering(offering);
            }

            HashSet loadedStudentIds = new HashSet();
            if (iIncludeCourseDemands) {
                List students = hibSession.createQuery(
                        "select distinct s from Student s " +
                        "left join fetch s.courseDemands as cd "+
                        "left join fetch cd.courseRequests as cr "+
                        "where s.session.uniqueId=:sessionId").
                        setLong("sessionId",session.getUniqueId().longValue()).
                        setFetchSize(1000).list();
                for (Iterator i=students.iterator();i.hasNext();) {
                    org.unitime.timetable.model.Student s = (org.unitime.timetable.model.Student)i.next();
                    if (s.getCourseDemands().isEmpty()) continue;
                    Student student = loadStudent(s, courseTable, classTable);
                    if (student!=null)
                        getModel().addStudent(student);
                    if (s.getExternalUniqueId()!=null)
                        loadedStudentIds.add(s.getExternalUniqueId());
                }
            }

            if (iIncludeLastLikeStudents) {
                Hashtable classAssignments = null;
                if (iIncludeUseCommittedAssignments) {
                    classAssignments = new Hashtable();
                    for (Iterator i=hibSession.createQuery("select distinct se.studentId, se.clazz.uniqueId from StudentEnrollment se where "+
                            "se.solution.commited=true and se.solution.owner.session.uniqueId=:sessionId").
                            setLong("sessionId",session.getUniqueId().longValue()).iterate();i.hasNext();) {
                        Object[] o = (Object[])i.next();
                        Long studentId = (Long)o[0];
                        Long classId = (Long)o[1];
                        HashSet classIds = (HashSet)classAssignments.get(studentId);
                        if (classIds==null) {
                            classIds = new HashSet();
                            classAssignments.put(studentId, classIds);
                        }
                        classIds.add(classId);
                    }
                }

                Hashtable lastLikeStudentTable = new Hashtable();
                for (Iterator i=hibSession.createQuery(
                    "select d, c.uniqueId from LastLikeCourseDemand d left join fetch d.student s, CourseOffering c left join c.demandOffering cx " +
                    "where d.subjectArea.session.uniqueId=:sessionId and c.subjectArea.session.uniqueId=:sessionId and " +
                    "((c.permId=null and d.subjectArea=c.subjectArea and d.courseNbr=c.courseNbr ) or "+
                    " (c.permId!=null and c.permId=d.coursePermId) or "+
                    " (cx.permId=null and d.subjectArea=cx.subjectArea and d.courseNbr=cx.courseNbr) or "+
                    " (cx.permId!=null and cx.permId=d.coursePermId)) "+
                    "order by s.uniqueId, d.priority, d.uniqueId").
                    setLong("sessionId",session.getUniqueId().longValue()).list().iterator();i.hasNext();) {
                    Object[] o = (Object[])i.next();
                    LastLikeCourseDemand d = (LastLikeCourseDemand)o[0];
                    org.unitime.timetable.model.Student s = (org.unitime.timetable.model.Student)d.getStudent();
                    Long courseOfferingId = (Long)o[1];
                    if (s.getExternalUniqueId()!=null && loadedStudentIds.contains(s.getExternalUniqueId())) continue;
                    loadLastLikeStudent(hibSession, d, s, courseOfferingId, lastLikeStudentTable, courseTable, classTable, classAssignments);
                }
                for (Enumeration e=lastLikeStudentTable.elements();e.hasMoreElements();) {
                    Student student = (Student)e.nextElement();
                    getModel().addStudent(student);
                }
                if (classAssignments!=null && !classAssignments.isEmpty()) {
                    for (Request request: getModel().variables()) {
                        if (request.getInitialAssignment()==null) continue;
                        Set conflicts = getModel().conflictValues(getAssignment(), request.getInitialAssignment());
                        if (conflicts.isEmpty())
                        	getAssignment().assign(0, request.getInitialAssignment());
                        else
                            sLog.debug("Unable to assign "+request.getInitialAssignment()+", conflicts: "+conflicts);
                    }
                }
                fixWeights();
            }

            tx.commit();
        } catch (Exception e) {
            tx.rollback();
            throw new RuntimeException(e);
        } finally {
            hibSession.close();
        }
    }

}


text:
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>common</pattern>
        </encoder>
    </appender>

    <appender-ref ref="CONSOLE"/>
</configuration>


text:
<?php

namespace App\EventListener;

use App\MainBundle\Document\ShoppingCart;
use App\MainBundle\Document\User;
use App\Service\ShopCartService;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

class LoginListener
{
    protected $container;

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {
        /** @var \Doctrine\ODM\MongoDB\DocumentManager $dm */
        $dm = $this->container->get('doctrine_mongodb')->getManager();
        /** @var User $user */
        $user = $event->getAuthenticationToken()->getUser();

        // Update shopping cart owner ID
        /** @var ShopCartService $shopCartService */
        $shopCartService = $this->container->get('app.shop_cart');
        $sessionId = $shopCartService->getSessionId();

        $shoppingCartRepository = $dm->getRepository(ShoppingCart::class);
        $shoppingCarts = $shoppingCartRepository->findBy([
            'sessionId' => $sessionId
        ]);
        if (!empty($shoppingCarts)) {
            /** @var ShoppingCart $shoppingCart */
            foreach ($shoppingCarts as $shoppingCart) {
                $shoppingCart->setOwnerId($user->getId());
            }
            $dm->flush();
        }
    }
}


text:
#include "stdafx.h"

#include <d3d10.h>
#include <d3dx10.h>

#include "Direct3D10Exception.h"

#include "BlendState1.h"
#include "BlendStateDescription1.h"
#include "Device10_1.h"

using namespace System;
using namespace SlimDX::Direct3D10;

namespace SlimDX
{
namespace Direct3D10_1
{
	BlendState1::BlendState1( ID3D10BlendState1* pointer, ComObject^ owner )
		: BlendState( pointer, owner )
	{
	}

	BlendState1::BlendState1( IntPtr pointer )
		: BlendState( pointer )
	{
	}

	BlendState1^ BlendState1::FromPointer( ID3D10BlendState1* pointer, ComObject^ owner, ComObjectFlags flags )
	{
		return ComObject::ConstructFromPointer<BlendState1, ID3D10BlendState1>( pointer, owner, flags );
	}

	BlendState1^ BlendState1::FromPointer( IntPtr pointer )
	{
		return ComObject::ConstructFromUserPointer<BlendState1>( pointer );
	}

	BlendState1^ BlendState1::FromDescription( Device1^ device, BlendStateDescription1 description )
	{
		if( device == nullptr )
			throw gcnew ArgumentNullException( "device" );

		ID3D10BlendState1* state = 0;
		D3D10_BLEND_DESC1 nativeDescription = description.CreateNativeVersion();

		if( RECORD_D3D10( device->InternalPointer->CreateBlendState1( &nativeDescription, &state ) ).IsFailure )
			return nullptr;

		return FromPointer( state );
	}

	BlendStateDescription1 BlendState1::Description::get()
	{
		D3D10_BLEND_DESC1 description;
		InternalPointer->GetDesc1( &description );
		return BlendStateDescription1( description );
	}
}
}


text:
1. [AWS Lambda Supports C# (.NET Core 2.0)](https://aws.amazon.com/about-aws/whats-new/2018/01/aws-lambda-supports-c-sharp-dot-net-core-2-0/)
1. [Bootstrap 4](http://blog.getbootstrap.com/2018/01/18/bootstrap-4/)
1. [Serverless ASP.NET Core 2.0 Applications](https://aws.amazon.com/blogs/developer/serverless-asp-net-core-2-0-applications/)
1. [.NET Core 2.0 support for App Service on Linux](https://azure.microsoft.com/en-us/updates/net-core-2-0-support-for-app-service-on-linux/)
1. [ASP.NET Core 2.1 roadmap](https://blogs.msdn.microsoft.com/webdev/2018/02/02/asp-net-core-2-1-roadmap/)
1. [ASP.NET Core in Action - MVC in ASP.NET Core](https://andrewlock.net/asp-net-core-in-action-mvc-in-asp-net-core/)
1. [AWS Lambda – use the invocation context to better handle slow HTTP responses](http://theburningmonk.com/2018/01/aws-lambda-use-the-invocation-context-to-better-handle-slow-http-responses/)
1. [I'm afraid you're thinking about AWS Lambda cold starts all wrong](http://theburningmonk.com/2018/01/im-afraid-youre-thinking-about-aws-lambda-cold-starts-all-wrong/)
1. [AWS Lambda – should you have few monolithic functions or many single-purposed functions?](http://theburningmonk.com/2018/01/aws-lambda-should-you-have-few-monolithic-functions-or-many-single-purposed-functions/)
1. [AWS Lambda – how best to manage shared code and shared infrastructure](http://theburningmonk.com/2018/02/aws-lambda-how-best-to-manage-shared-code-and-shared-infrastructure/)
1. [TypedRouting for ASP.NET Core MVC 2](https://www.strathweb.com/2018/01/typedrouting-for-asp-net-core-mvc-2/)
1. [Stacktrace improvements in .NET Core 2.1](https://www.ageofascent.com/2018/01/26/stack-trace-for-exceptions-in-dotnet-core-2.1/)
1. [HTTPS deployment tips](https://scotthelme.co.uk/https-deployment-tips/)

## Tooling & Libraries

1. [PowerShell Core 6.0 Generally Available (GA) and Supported!](https://blogs.msdn.microsoft.com/powershell/2018/01/10/powershell-core-6-0-generally-available-ga-and-supported/)
1. [Announcing PolicyServer](https://leastprivilege.com/2018/01/17/announcing-policyserver/)
1. [Akka.NET v1.3.3 Stable Release](https://github.com/akkadotnet/akka.net/releases/tag/v1.3.3)
1. [Lose the Cables - Make Deploying to an iOS or tvOS Device Easier](https://blog.xamarin.com/lose-cables-make-deploying-ios-tvos-device-easier/)
1. [Respawn 3.0 Released](https://jimmybogard.com/respawn-3-0-released/)
1. [How Respawn Works](https://jimmybogard.com/how-respawn-works/)
1. [LinqAF - A series of questionable ideas](https://kevinmontrose.com/2018/01/16/linqaf-a-series-of-questionable-ideas/)
1. [LinqAF - Replacing LINQ and not allocating](https://kevinmontrose.com/2018/01/17/linqaf-replacing-linq-and-not-allocating/)
1. [LinqAF - Generating way too much code](https://kevinmontrose.com/2018/01/18/linqaf-generating-way-too-much-code/)
1. [LinqAF - All the operations](https://kevinmontrose.com/2018/01/19/linqaf-all-the-operations/)
1. [LinqAF - Allocating](https://kevinmontrose.com/2018/01/22/linqaf-allocating/)
1. [LinqAF - SelectMany and boxing](https://kevinmontrose.com/2018/01/23/linqaf-selectmany-and-boxing/)
1. [LinqAF - Testing](https://kevinmontrose.com/2018/01/24/linqaf-testing/)
1. [LinqAF - Benchmarks](https://kevinmontrose.com/2018/01/25/linqaf-benchmarks/)

## Architecture & Databases

1. [Data-First Architecture](http://anthonylloyd.github.io/blog/2018/02/01/architecture-data-first)
1. [The Gemba Walk for Designing Software](https://jimmybogard.com/the-gemba-walk-for-designing-software/)
1. [Designing Microservice Messages - A Primer](https://jimmybogard.com/designing-microservices/)
1. [IntegrationTest](https://martinfowler.com/bliki/IntegrationTest.html)
1. [An Easier Way of Pivoting Data in SQL Server](https://www.red-gate.com/simple-talk/sql/t-sql-programming/easier-way-pivoting-data-sql-server/)
1. [Inline Index Definition](https://www.red-gate.com/simple-talk/blogs/inline-index-definition/)
1. [Degree of Duplication](https://www.red-gate.com/simple-talk/opinion/opinion-pieces/degree-of-duplication/)
1. [Matters of Timing in Concurrency](https://www.red-gate.com/simple-talk/blogs/matters-timing-concurrency/)
1. [Designing a Cosmos DB database](https://blogs.msdn.microsoft.com/premier_developer/2018/01/31/designing-a-cosmos-db-database/)
1. [Operating System Best Practice Configurations for SQL Server](https://blogs.msdn.microsoft.com/docast/2018/02/01/operating-system-best-practice-configurations-for-sql-server)

## Programming Languages

1. [Extending the async methods in C#](https://blogs.msdn.microsoft.com/seteplia/2018/01/11/extending-the-async-methods-in-c/)
1. [default interface methods](https://github.com/dotnet/csharplang/blob/master/proposals/default-interface-methods.md)
1. [Accessing Tuples at Runtime using Reflection](https://www.danielcrabtree.com/blog/365/accessing-tuples-at-runtime-using-reflection)
1. [Function isomorphisms](http://blog.ploeh.dk/2018/01/22/function-isomorphisms/)
1. [Argument list isomorphisms](http://blog.ploeh.dk/2018/01/29/argument-list-isomorphisms/)
1. [Reinventing MVC pattern for web programming with F#](http://kcieslak.io/Reinventing-MVC-for-web-programming-with-F)
1. [Eight reasons to learn F#](https://medium.com/real-world-fsharp/eight-reasons-to-learn-f-fcb2bef64d7a)
1. [Announcing TypeScript 2.7](https://blogs.msdn.microsoft.com/typescript/2018/01/31/announcing-typescript-2-7/)
1. [Easy way to create a C# lambda expression from a string (with Roslyn)](https://www.strathweb.com/2018/01/easy-way-to-create-a-c-lambda-expression-from-a-string-with-roslyn/)
1. [A Sort Of Problem](http://blog.marcgravell.com/2018/01/a-sort-of-problem.html)
1. [More Of A Sort Of Problem](http://blog.marcgravell.com/2018/01/more-of-sort-of-problem.html)
1. [Sorting myself out, extreme edition](http://blog.marcgravell.com/2018/01/sorting-myself-out-extreme-edition.html)

## Runtime

1. [Math.Abs is slow](https://github.com/dotnet/corefx/issues/26253)
1. [Object header get complicated](https://mycodingplace.wordpress.com/2018/01/10/object-header-get-complicated/)
1. [Mono and WebAssembly - Updates on Static Compilation](http://www.mono-project.com/news/2018/01/16/mono-static-webassembly-compilation/)
1. [Resources for Learning about .NET Internals](http://mattwarren.org/2018/01/22/Resources-for-Learning-about-.NET-Internals/)
1. [Added Grisu3 algorithm support for double.ToString()](https://github.com/dotnet/coreclr/pull/14646)
1. [Allocation is cheap... until it is not](http://tooslowexception.com/allocation-is-cheap-until-it-is-not/)
1. [Zero Garbage Collector for .NET Core 2.1 and ASP.NET Core 2.1](http://tooslowexception.com/zero-garbage-collector-for-net-core-2-1-and-asp-net-core-2-1/)
1. [.NET Core 2.1 Roadmap](https://blogs.msdn.microsoft.com/dotnet/2018/02/02/net-core-2-1-roadmap/)

## Other

1. [Thanks a Million, Jon Skeet!](https://stackoverflow.blog/2018/01/15/thanks-million-jon-skeet/)
1. [How To Measure the Working Set Size on Linux](http://www.brendangregg.com/blog/2018-01-17/measure-working-set-size.html)
1. [Some thoughts on security after ten years of qmail 1.0](https://blog.acolyer.org/2018/01/17/some-thoughts-on-security-after-ten-years-of-qmail-1-0/)
1. [CLR vs JVM - How the Battle Between C# and Java Extends to the VM-Level](https://blog.takipi.com/clr-vs-jvm-how-the-battle-between-net-and-java-extends-to-the-vm-level/)
1. [I Am a 9 to 5 Developer (And So Can You!)](https://exceptionnotfound.net/i-am-a-9-to-5-developer-and-so-can-you/)
1. [All Code Is Disposable, Just As It Should Be](https://exceptionnotfound.net/all-code-is-disposable-just-like-it-should-be/)