UNPKG

generator-beez

Version:
5,039 lines 178 kB
/**
 * @name base.js<beez-mvcr>
 * @author Kei Funagayama <funagayama_kei@cyberagent.co.jp>
 * copyright (c) Cyberagent Inc.
 * @overview base class of managed object
 */

(function (global) {

    define('beez-mvcr/jsonpath',['require','exports','module','beez.core'],function (require, exports, module) {
        

        var beez = require('beez.core');
        var _ = beez.vendor._;

        // -------------------
        // JSONPath

        var cache = {}; // -- jsonpath implements


        /* JSONPath 0.8.0 - XPath for JSON
         *
         * Copyright (c) 2007 Stefan Goessner (goessner.net)
         * Licensed under the MIT (MIT-LICENSE.txt) licence.
         *
         * @license https://github.com/s3u/JSONPath
         */
        var jsonPath = function jsonPath(obj, expr, arg, testManaged) {
            var P = {
                resultType: arg && arg.resultType || "VALUE",
                flatten: arg && arg.flatten || false,
                wrap: (arg && arg.hasOwnProperty('wrap')) ? arg.wrap : true,

                normalize: function (expr) {
                    if (cache[expr]) {
                        return cache[expr];
                    }

                    var subx = [];
                    var ret =
                            expr.replace(/[\['](\??\(.*?\))[\]']/g, function ($0, $1) {
                                return "[#" + (subx.push($1) - 1) + "]";
                            })
                            .replace(/'?\.'?|\['?/g, ";")
                            .replace(/;;;|;;/g, ";..;")
                            .replace(/;$|'?\]|'$/g, "")
                            .replace(/#([0-9]+)/g, function ($0, $1) {
                                return subx[$1];
                            });

                    cache[expr] = ret;
                    return ret;
                },
                asPath: function (path) {
                    var x = path.split(";"), p = "$";
                    for (var i = 1, n = x.length; i < n; i++) {
                        p += /^[0-9*]+$/.test(x[i]) ?
                            ("[" + x[i] + "]") : ("['" + x[i] + "']");
                    }
                    return p;
                },
                store: function (p, v) {
                    if (p) {
                        if (P.resultType === "PATH") {
                            P.result[P.result.length] = P.asPath(p);
                        } else {
                            if (_.isArray(v) && P.flatten) {
                                if (!P.result) { P.result = []; }
                                if (!_.isArray(P.result)) { P.result = [P.result]; }
                                P.result = P.result.concat(v);
                            } else {
                                if (P.result) {
                                    if (!_.isArray(P.result)) {
                                        P.result = [P.result];
                                    }

                                    if (_.isArray(v) && P.flatten) {
                                        P.result = P.result.concat(v);
                                    } else {
                                        P.result[P.result.length] = v;
                                    }
                                } else {
                                    P.result = v;
                                }
                            }
                        }
                    }
                    return !!p;
                },
                trace: function (expr, val, path) {

                    if (expr) {
                        var x = expr.split(";"), loc = x.shift();
                        x = x.join(";");
                        if (val && val.hasOwnProperty(loc)) {
                            P.trace(x, val[loc], path + ";" + loc);
                        } else if (loc === "*") {
                            P.walk(loc, x, val, path, function (m, l, x, v, p) {
                                P.trace(m + ";" + x, v, p);
                            });
                        } else if (loc === "..") {
                            P.trace(x, val, path);
                            P.walk(loc, x, val, path, function (m, l, x, v, p) {
                                typeof v[m] === "object" &&
                                    P.trace("..;" + x, v[m], p + ";" + m);
                            });
                        } else if (/,/.test(loc)) { // [name1,name2,...]
                            for (
                                var s = loc.split(/'?,'?/), i = 0, n = s.length;
                                i < n;
                                i++
                            ) {
                                P.trace(s[i] + ";" + x, val, path);
                            }
                        } else if (/^\(.*?\)$/.test(loc)) {// [(expr)]
                            /* jshint evil: true */
                            P.trace(
                                P.evaluate(
                                    loc, val, path.substr(path.lastIndexOf(";") + 1)
                                ) + ";" + x, val, path);
                        } else if (/^\?\(.*?\)$/.test(loc)) {// [?(expr)]
                            P.walk(loc, x, val, path, function (m, l, x, v, p) {
                                /* jshint evil: true */
                                if (P.evaluate(l.replace(/^\?\((.*?)\)$/, "$1"), v[m], m)) {
                                    P.trace(m + ";" + x, v, p);
                                }
                            });
                        } else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) {
                            // [start:end:step]  phyton slice syntax
                            P.slice(loc, x, val, path);
                        }
                    } else {
                        if (val && (_.isArray(val) || testManaged(val))) {
                            P.store(path, val);
                        }
                    }
                },
                walk: function (loc, expr, val, path, f) {
                    if (val instanceof Array) {
                        for (var i = 0, n = val.length; i < n; i++) {
                            if (i in val) {
                                f(i, loc, expr, val, path);
                            }
                        }
                    }
                    else if (typeof val === "object") {

                        //
                        // check if the object is managing object
                        // to avoid walking non-beez structure object
                        // added by maginemu
                        //
                        if (testManaged(val)) {
                            for (var m in val) {
                                if (val.hasOwnProperty(m)) {
                                    f(m, loc, expr, val, path);
                                }
                            }
                        }
                    }
                },
                slice: function (loc, expr, val, path) {
                    if (val instanceof Array) {
                        var len = val.length, start = 0, end = len, step = 1;
                        loc.replace(
                                /^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g,
                            function ($0, $1, $2, $3) {
                                start = parseInt($1 || start, 10);
                                end = parseInt($2 || end, 10);
                                step = parseInt($3 || step, 10);
                            }
                        );
                        start = (start < 0) ? Math.max(0, start + len) : Math.min(len, start);
                        end   = (end < 0)   ? Math.max(0, end + len)   : Math.min(len, end);
                        for (var i = start; i < end; i += step) {
                            P.trace(i + ";" + expr, val, path);
                        }
                    }
                },
                evaluate: function (x, _v, _vname) {
                    /* jshint evil: true */
                    try {
                        return $ && _v && eval(x);
                    } catch (e) {
                        throw new SyntaxError("jsonPath: " + e.message + ": " + x.replace(/\^/g, "_a"));
                    } // `@` usecase removed from original
                }
            };
            P.result = P.wrap === true ? [] : undefined;

            var $ = obj;
            if (expr && obj && (P.resultType === "VALUE" || P.resultType === "PATH")) {
                P.trace(
                    P.normalize(expr).replace(/^\$;/, ""),
                    obj,
                    "$"
                );
                if (!_.isArray(P.result) && P.wrap) { P.result = [P.result]; }
                return P.result ? P.result : false;
            }
            return undefined;
        };

        return jsonPath;
    });

})(this);

/**
 * @name base.js<beez-mvcr>
 * @author Kazuma MISHIMAGI <mishimagi_kazuma@cyberagent.co.jp">
 * copyright (c) Cyberagent Inc.
 * @overview base class of managed object
 */

(function (global) {

    define('beez-mvcr/base',['require','exports','module','beez.core','beez-mvcr/jsonpath'],function (require, exports, module) {
        

        var beez = require('beez.core');
        var _ = beez.vendor._;

        var jsonPath = require('beez-mvcr/jsonpath');

        var logger = beez.getLogger('beez.mvcr.base');

        // -------------------
        // ManagerBase

        /**
         * It provides a set of methods to deal with it and tree structure simple of Object.
         * Object of ManagerBase has properties of specific management
         *
         * @class
         * @name ManagerBase
         *
         * @example
         * var manager = new ManagerBase('idx');
         *
         * manager.add('/', {idx:'someObj'});
         * manager.get('/someObj') // => {idx:'someObj'}
         *
         * manager.add('/', [{idx:'button', name:'a'}, {idx:'button', name:'b'}]);
         * manager.get('/button') // => [{idx:'button', name:'a'}, {idx:'button', name:'b'}]
         * manager.get('/button[0]') // => {idx:'button', name:'a'}
         */
        var ManagerBase = beez.extend(
            'beez.manager.ManagerBase',
            function ManagerBase() {},
            {

                /**
                 * @constructor
                 * @memberof ManagerBase
                 * @param {String} idxProp base index name
                 */
                constructor: function constructor(idxProp) {

                    /**
                     * Objects that are managed
                     */
                    this.objs = {};

                    /**
                     * The assignment to the $ indicates the root
                     */
                    this.objs[idxProp] = '$';

                    /**
                     * Index for management
                     */
                    this._idxProp = idxProp || '';

                    /**
                     * Run initialize
                     */
                    this.initialize.apply(this, arguments);
                },

                /**
                 * Constructor
                 *
                 * @memberof ManagerBase
                 */
                initialize: function initialize() {},

                /**
                 * Get idx of object
                 *
                 * @memberof ManagerBase
                 * @param {ManagerBase} obj
                 * @public
                 * @returns {String} idx
                 */
                getIdx: function getIdx(obj) {
                    return obj[this._idxProp];
                },


                /**
                 * put under control the specified Object
                 *
                 * @memberof ManagerBase
                 * @instance
                 * @param {String} prefix
                 * @param {Object|Array<Object>} obj
                 *
                 * @example
                 * var mainModel = {
                 *   follower: [
                 *     followerModel1,
                 *     folloewrModel2
                 *   ]
                 * }
                 *
                 * var followerModel3, followingModel, buttonModel;
                 * followerModel3.midx = 'follower';
                 * followingModel.midx = 'following';
                 * buttonModel.midx = 'button';
                 *
                 * manager.model.add('/main', [followerModel, followingModel]);
                 *
                 * -> mainModel : {
                 *   follower:[
                 *     followerModel1
                 *     folloewrModel2,
                 *     folloewrModel3
                 *   ],
                 *   following:[
                 *     followingModel
                 *   ]
                 * }
                 *
                 * manager.model.add('/main', button);
                 * -> mainModel : {
                 *   follower:[
                 *     followerModel1,
                 *     folloewrModel2,
                 *     folloewrModel3
                 *   ],
                 *   following:[
                 *     followingModel
                 *   ],
                 *   button: buttonModel
                 * }
                 */
                add: function add(prefix, obj) {
                    var parent = this.get(prefix); // search parent from root object

                    // get parent or create waiting object
                    if (!parent) { throw new beez.Error('no parent exists. path: ' + prefix); }
                    if (_.isArray(parent)) { throw new beez.Error('parent is Array. Specify one by using `[number]` selector. parent: ' + parent); }

                    if (_.isArray(obj)) { // add as the children
                        _.each(obj, function (_obj) {
                            _obj.prefix = prefix; // keep prefix
                            var idx = this.getIdx(_obj);
                            if (!parent[idx]) { // make array
                                parent[idx] = [];
                            }
                            parent[idx].push(_obj);

                        }, this);
                    } else {
                        obj.prefix = prefix; // keep prefix
                        var idx = this.getIdx(obj);
                        if (parent[idx]) {
                            throw new beez.Error(
                                'Obj: adding object to same parent with same index. Add obj as Array to add several objs into same index. idx: ' + this.getIdx(obj));
                        }
                        parent[idx] = obj;
                    }

                    return this;
                },


                /**
                 * will remove from management the object that is specified in the path
                 *
                 * @memberof ManagerBase
                 * @instance
                 * @param {String} path
                 */
                remove: function remove(path) {
                    var objs = this.get(path);
                    // get all children
                    var children = [];
                    var deletes;

                    if (!objs) { return; }

                    // now `views` is always Array
                    if (!_.isArray(objs)) { objs = [objs]; } // array-nize

                    _.each(objs, function (v) {
                        var c = this.getChildrenAll(v);
                        children = children.concat(c);
                    }, this);

                    // list to delete
                    // is children and this views
                    deletes = children.concat(objs);
                    // remove parent's reference
                    _.each(deletes, function (del) {
                        this.deleteFromParent(del);
                    }, this);

                    // call dispose of each views
                    _.each(deletes, function (v) {
                        //v.remove();
                        v.dispose && v.dispose();
                    });
                },

                /**
                 * Returns whether the object can be added to the manager.
                 *
                 * @memberof ManagerBase
                 * @instance
                 * @param {Object} obj
                 * @returns {boolean}
                 */
                isAddable: function (obj) {
                    return !!this.getIdx(obj);
                },


                /**
                 * get an Object that is specified in the path
                 * Warnning: which was replaced by the '/' '.'.
                 *           no need for root $
                 *
                 * @see https://github.com/s3u/JSONPath
                 * @memberof ManagerBase
                 * @instance
                 * @param {String} path
                 * @returns {Object}
                 */
                get: function get(path) {
                    if (path === undefined || typeof(path) !== 'string') {
                        return undefined;
                    }

                    if (/^\/$/.test(path)) {
                        return this.objs;
                    }

                    var self = this;
                    path = '$' + path.replace(/\//g, '.');
                    var result = jsonPath(
                        this.objs,
                        path,
                        {wrap: false},
                        function testAddable(obj) {
                            return self.isAddable(obj);
                        });
                    if (!result) {
                        return undefined;
                    }
                    return result;
                },


                /**
                 * get the parent. If obj is an array: I get the information from the parent of the first element
                 *
                 * @memberof ManagerBase
                 * @instance
                 * @param {Object|Array.<Object>} obj
                 */
                getParent: function getParent(obj) {
                    if (_.isArray(obj)) {
                        return this.get(obj[0].prefix);
                    }
                    return this.get(obj.prefix);
                },


                /**
                 * will remove from the parent, a reference to objct specified.
                 *
                 * @memberof ManagerBase
                 * @instance
                 * @param {Object|Array.<Object>} obj
                 */
                deleteFromParent: function deleteFromParent(obj) {
                    if (!obj) {
                        return;
                    }

                    var parent = this.getParent(obj);
                    if (_.isArray(obj)) {
                        delete parent[this.getIdx(obj[0])];
                    } else {
                        delete parent[this.getIdx(obj)];
                    }
                },


                /**
                 * get the child list of just under
                 *
                 * @memberof ManagerBase
                 * @instance
                 * @param {Object} obj
                 * @return {Array.<Object>}
                 */
                getChildren: function getChildren(obj) {
                    var result = [];
                    var self = this;

                    var _walk = function _walk(list) {
                        _.each(list, function (item) {
                            if (!item) {
                                return;
                            }

                            if (_.isArray(item)) {
                                _walk(item);
                            } else if (self.getIdx(item)) {
                                result.push(item);
                            }
                        });
                    };

                    _walk(obj);
                    return result;
                },


                /**
                 * You get as an array all the specified Object (recursively)
                 *
                 * @memberof ManagerBase
                 * @param {Object} data
                 * @return {Array.<Object>}
                 */
                getChildrenAll: function getChildrenAll(data) {
                    var result = [];
                    var self = this;

                    var _walk = function _walk(obj) {
                        var list = obj;
                        if (!_.isArray(obj)) {
                            list = _.values(obj);
                        }
                        _.each(list, function (item, idx) {
                            if (!item) {
                                return;
                            }
                            if (_.isArray(item)) {
                                _walk(item);

                            } else if (self.getIdx(item)) {

                                if (!item.prefix || !item.manager) { // Item that is not managed to ignore
                                    logger.warn("Manager ignore the Object haven't been manaegd.", item);
                                    // result.push(item); // Do not ignore
                                    return;
                                }

                                // Ignore the member variable Object has set manually by user.
                                if (obj[self._idxProp] !== '$' && !_.isArray(obj) && item.getParent()[self._idxProp] !== obj[self._idxProp]) {
                                    logger.warn("Manager ignore the Object haven't been manaegd.",
                                                'Path that is managed:', self.pathOf(item), // The paths managed the Object of interest
                                                'Path to the specified:', self.pathOf(obj) // The actual path
                                                );
                                    return;
                                }
                                _walk(item); // Child is at the beginning of the Array
                                result.push(item);

                            }
                        });
                    };

                    // walk start
                    _walk(data);
                    return result;
                },


                /**
                 * Returns the path of the Object being managed. If the Object is array, returns the first element.
                 *
                 * @memberof ManagerBase
                 * @param {String} prefix
                 * @param {Object|Array} obj
                 * @throw {Error} obj is empty array
                 * @throw {Error} object.prefix does not exist
                 * @return {String}
                 */
                pathOf: function pathOf(obj) {
                    var prefix = '';
                    if (_.isArray(obj)) {
                        if (_.isEmpty(obj)) {
                            throw new beez.Error('pathOf: obj is empty array.');
                        }
                        obj = obj[0];
                    }

                    prefix = obj.prefix;

                    if (!prefix) {
                        throw new beez.Error('pathOf: object.prefix does not exist.');
                    }
                    return prefix + ((/^\/$/.test(prefix)) ? '' : '/') + this.getIdx(obj);
                },


                /**
                 * Returns the information Objects are managed.
                 *
                 * @memberof ManagerBase
                 * @return {Object}
                 */
                trace: function trace() {

                    var pairs = {};

                    // all children
                    var all = this.getChildrenAll(this.objs || {});

                    // for each child, make path & store
                    var self = this;
                    _.each(all, function (obj) {

                        if (!obj) {
                            return;
                        }

                        // make path
                        var key;
                        if (obj.prefix === '/') { // if parent is root
                            key = obj.prefix + self.getIdx(obj);
                        } else {
                            key = obj.prefix + '/' + self.getIdx(obj);
                        }

                        // store
                        if (pairs[key]) { // if already exists
                            if (!_.isArray(pairs[key])) {
                                // at first time, make array
                                pairs[key] = [pairs[key]];
                            }
                            pairs[key].push(obj); // push
                        } else {
                            // as sigle object
                            pairs[key] = obj;
                        }
                    });

                    return pairs;
                },
                dispose: function dispose() {
                    delete this.objs;
                    delete this._idxProp;
                }
            }
        );

        // -------------------
        // Base

        /**
         * This is the base class of an Object managed by the Manager.
         *
         * @class
         * @name Base
         */
        var Base = beez.extend(
            'beez.mvcr.Base',
            function Base() {},
            {
                /**
                 * get the first element. Gets the parent. If object is an array, sets the first
                 *
                 * @memberof Base
                 * @instance
                 */
                getParent: function getParent() {
                    return this.manager.getParent(this);
                },

                /**
                 * delete the reference of Object from a parent
                 *
                 * @memberof Base
                 * @instance
                 */
                deleteFromParent: function deleteFroParent() {
                    return this.manager.deleteFromParent(this);
                },

                /**
                 * I acquire a list of children underneath.
                 *
                 * @memberof Base
                 * @instance
                 * @return {Array.<Object>}
                 */
                getChildren: function getChildren() {
                    return this.manager.getChildren(this);
                },

                /**
                 * I acquire all Object of the descendant as an arrangement.
                 *
                 * @memberof Base
                 * @instance
                 * @return {Array.<Object>}
                 */
                getChildrenAll: function getChildrenAll() {
                    return this.manager.getChildrenAll(this);
                },


                /**
                 * Sets the object beneath the specified prefix.
                 *
                 * @memberof Base
                 * @param {String} prefix prefix name
                 */
                alias: function alias(prefix) {
                    return this.manager.add(prefix, this);
                }
            }
        );

        return {
            ManagerBase: ManagerBase,
            Base: Base
        };

    });

})(this);

/**
 * @fileOverview Model
 * @name model.js<beez-mvcr>
 * @author Kazuma Mishimagi <mishimagi_kazuma@cyberagent.co.jp>
 * @overview Model management functions
 */

(function (global) {

    /**
     * Model module
     * @exports beez-mvcr/model
     */
    define('beez-mvcr/model',['require','exports','module','beez.core','backbone','beez-mvcr/base'],function (require, exports, module) {
        

        var beez = require('beez.core');
        var _ = beez.vendor._;
        var Backbone = require('backbone');
        var $ = beez.vendor.$;

        var base = require('beez-mvcr/base');
        var Base = base.Base;
        var ManagerBase = base.ManagerBase;

        var logger = beez.getLogger('beez.mvcr.model');

        // -------------------
        // ModelManagerAsync

        /**
         * Model management class. asynchronous
         *
         * @class
         * @name ModelManagerAsync
         * @extends {Bucks}
         */
        var ModelManagerAsync = beez.Bucks.extend(
            'beez.mvcr.ModelManagerAsync',
            {
                initialize: function initialize(manager) {
                    this.manager = manager;
                    this.current = undefined;
                    this.root = undefined;
                },

                /**
                 * set root
                 *
                 * @memberof ModelManagerAsync
                 * @instance
                 * @return {ModelManagerAsync}
                 */
                //root: function root(RootView) {
                //var self = this;
                //    return this.then(function () {
                //        return self.manager.root(RootView);
                //    });
                //},

                /**
                 * Generate Model.
                 *
                 * @memberof ModelManagerAsync
                 * @instance
                 * @param {String} prefix
                 * @param {Model|Array<Model>} Model Generate model object.
                 * @param {Object|Array<Object>} [attributes] Model to generate a attributes
                 * @param {Object|Array<Object>} [options] Model to generate a options
                 * @return {ModelManagerAsync}
                 */
                create: function create(prefix, Model, attributes, options) {
                    var self = this;
                    return this.then(function () {
                        var v = self.manager.create(prefix, Model, attributes, options);
                        self.root = self.current = v;
                        self.create = function create_twice() {
                            throw new beez.Error('create called more than once!');
                        };
                        return v;
                    });
                },

                /**
                 * Generate collection.
                 *
                 * @memberof ModelManagerAsync
                 * @instance
                 * @param {String} prefix
                 * @param {Collection|Array<Model>} Collection Generate collection object.
                 * @param {Array<Object>} models Model(s)
                 * @param {Object|Array<Object>} options Collection to generate a options
                 * @return {ModelManagerAsync}
                 */
                createCollection: function createCollection(prefix, Collection, models, options) {
                    var self = this;
                    return this.then(function () {
                        var c = self.manager.createCollection(prefix, Collection, models, options);
                        self.root = self.current = c;
                        self.createCollection = function createCollection_twice() {
                            throw new beez.Error('create called more than once!');
                        };
                        return c;
                    });
                },

                /**
                 * Get the child Model
                 *
                 * @memberof ModelManagerAsync
                 * @instance
                 * @param {Model|Array<Model>} Model Generate model object.
                 * @param {Object|Array<Object>} [attributes] Model to generate a attributes
                 * @param {Object|Array<Object>} [options] Model to generate a options
                 * @return {ModelManagerAsync}
                 */
                child: function child(Model, attributes, options) {
                    var self = this;
                    return this.then(function () {
                        if (!self.root) {
                            throw new beez.Error('No chain root exists. `create` first.');
                        }
                        var prefix = self.manager.pathOf(self.current);
                        var v = self.manager.create(prefix, Model, attributes, options);
                        self.current = _.isArray(v) ? v[0] : v;
                    });
                },

                /**
                 * I acquire a parent of Model.
                 *
                 * @memberof ModelManagerAsync
                 * @instance
                 * @return {ModelManagerAsync}
                 */
                parent: function parent() {
                    var self = this;
                    return this.then(function () {
                        self.current = self.manager.getParent(self.current);
                        if (!self.current) {
                            throw new beez.Error('get parent failed');
                        }
                    });
                },


                /**
                 * The child and its brother of the parents of Model.
                 *
                 * @memberof ModelManagerAsync
                 * @instance
                 * @param {Model|Array<Model>} brother object.
                 * @param {Object|Array<Object>} [attributes] constructor a attributes
                 * @param {Object|Array<Object>} [options] constructor a options
                 * @return {ModelManagerAsync}
                 */
                bro: function bro(brother, attributes, options) {
                    return this.parent().child(brother, attributes, options);
                },


                /**
                 * Disposes of the instance
                 *
                 * @override
                 * @memberof ModelManagerAsync
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');
                    delete this.manager;
                    delete this.current;
                    if (this.root && this.root.dispose) {
                        this.root.dispose();
                    }
                    delete this.root;
                }
            }
        );


        // -------------------
        // ModelManager

        /**
         * ModelManager Class
         *
         * @class
         * @name ModelManager
         */
        var ModelManager = beez.extend(
            'beez.mvcr.ModelManager',
            ManagerBase,
            {
                /**
                 * Constructor
                 *
                 * @memberof ModelManager
                 */
                initialize: function initialize() {
                    var self = this;

                    ModelManager.__super__.initialize.apply(this, arguments);

                    // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
                    // Override this if you'd like to use a different library.
                    //beez.vendor.Backbone.ajax = this.ajax;

                    this._sync = beez.vendor.Backbone.sync;
                    beez.vendor.Backbone.sync = function sync(method, model, options) {
                        var configAjax = beez.config.ajax || {};
                        _.defaults(options || (options = {}), configAjax, {
                            dataType: 'json',
                            contentType: 'application/json',
                            emulateHTTP: false,
                            emulateJSON: false
                        });
                        self._sync.apply(this, arguments);
                    };
                },

                /**
                 * Generating ModelManagerAsync
                 *
                 * @memberof ModelManager
                 * @instance
                 * @return {ModelManagerAsync}
                 */
                async: function async() {
                    return new ModelManagerAsync(this);
                },

                /**
                 * Set the Root Model
                 *
                 * @memberof ModelManager
                 * @param {Model} RootModel
                 * @return {Model}
                 */
                root: function root(RootModel) {
                    var rootModel = new RootModel(this);
                    var root = this.get('/@');
                    if (root) {
                        throw new beez.Error('root already exists!');
                    }

                    if (rootModel.midx !== '@') {
                        throw new beez.Error('roots midx must be "@"');
                    }
                    this.add('/', rootModel);

                    return rootModel;
                },

                /**
                 * Generate Model. Add a managed object
                 *
                 * @memberof ModelManager
                 * @instance
                 * @param {String} prefix parent prefix.
                 * @param {Model|Array<Model>} Model Generate model object(s).
                 * @param {Object|Array<Object>} [attributes] Model to generate a attributes
                 * @param {Object|Array<Object>} [options] Model to generate a options
                 * @return {Model}
                 */
                create: function create(prefix, Model, attributes, options) {

                    if (!Model || (!_.isArray(Model) && typeof Model !== 'function')) {
                        var msg = 'Model does not exist / does not be funciton. ' + 'Specified prefix: ' + prefix;
                        throw new beez.Error(msg);
                    }

                    if (Model instanceof Collection) {
                        throw new beez.Error('Collection specified.  Use #createCollection instead.');
                    }

                    if (!prefix) { // prefix check
                        throw new beez.Error('No prefix specified. Creating:' + Model.name);
                    } else if (prefix.indexOf('/@') < 0) {
                        throw new beez.Error('prefix must started by "/@". Creating:' + Model.name);
                    }

                    if (!this.get(prefix)) { // no parent
                        throw new beez.Error('no parent exists. prefix: ' + prefix + ' ,  Please consider constructing in Controller and so on.');
                    }

                    if (_.isArray(Model)) {
                        return this._createArray(prefix, Model, attributes, options);
                    }

                    return this._createObj(prefix, Model, attributes, options);
                },

                _createObj: function _createObj(prefix, Model, attribute, option) {
                    var m = new Model(attribute, option, this);

                    if (!this.isAddable(m)) {
                        throw new beez.Error('index does not exists in the Model. :' + m);
                    }
                    this.add(prefix, m);

                    return m;
                },

                _createArray: function _createArray(prefix, Models, attributes, options) {
                    // make to array when params aren't array
                    if (attributes && !_.isArray(attributes)) {
                        attributes = [attributes];
                    }

                    if (options && !_.isArray(options)) {
                        options = [options];
                    }
                    var self = this;
                    var instances = [];
                    _.each(Models, function (C, idx) {
                        var attr = attributes ? attributes[idx] : undefined;
                        var opt = options ? options[idx] : undefined;
                        instances.push(new C(attr, opt, self));
                    });

                    _.each(instances, function (model) {
                        if (!this.isAddable(model)) {
                            throw new beez.Error('index does not exist in the Model. :' + model);
                        }
                    }, this);

                    this.add(prefix, instances);

                    return instances;
                },

                /**
                 * Generate collection.
                 *
                 * @memberof ModelManager
                 *
                 * @instance
                 * @param {String} prefix parent prefix
                 * @param {Collection} Collection Generate collection object.
                 * @param {Object} [attributes] Collection to generate a attributes
                 * @param {Object} [options] Collection to generate a options
                 * @return {Model}
                 */
                createCollection: function createCollection(prefix, Collection, models, options) {
                    if (!Collection || typeof Collection !== 'function') {
                        var msg = 'Collection does not exist / does not be funciton. ' +
                                'Specified prefix: ' + prefix;
                        throw new beez.Error(msg);
                    }

                    if (!prefix) { // prefix check
                        throw new beez.Error('No prefix specified. Creating:' + Collection.name);
                    }
                    if (prefix.indexOf('/@') < 0) {
                        throw new beez.Error('prefix must started by "/@". Creating:' + Collection.name);
                    }

                    var c = new Collection(models, options, this);

                    this.add(prefix, c);

                    return c;
                },

                _newAll: function _newAll(ctor, attributes, options) {

                    if (!ctor) {
                        throw new beez.Error('ctor does not exist.');
                    }

                    if (!_.isArray(ctor)) {
                        ctor = [ctor];
                    }

                    if (attributes && !_.isArray(attributes)) {
                        attributes = [attributes];
                    }

                    if (options && !_.isArray(options)) {
                        options = [options];
                    }


                    var instances = [];
                    _.each(ctor, function (C, idx) {
                        var attrs = attributes ? attributes[idx] : undefined;
                        var opts = options ? options[idx] : undefined;
                        instances.push(new C(attrs, opts));
                    });

                    return instances;
                },

                /**
                 * _decideBindedModel
                 *
                 * @memberof ModelManager
                 * @instance
                 * @private
                 * @param {Object} obj
                 * @param {Boolean} isCollection
                 * @return object
                 */
                _decideBindedModel: function _decideBindedModel(obj, isCollection) {
                    var model;
                    var returnedModel;
                    var children;

                    if (!isCollection) {
                        model = obj;
                        children = [];

                        _.each(model, function (v) {
                            var c = this.getChildrenAll(v);
                            children = children.concat(c);
                        }, this);

                        var candidates = children.concat(model);

                        // remove still binded models
                        var deletes = _.reject(candidates, function (d) {
                            return d.isBinded();
                        });

                        // models in diff still have some bindings
                        var diff = _.difference(candidates, deletes);
                        _.each(diff, function (model) {
                            throw new beez.Error('a disposing model have some bindings. models cid: ' + model.cid);
                        });

                        returnedModel = deletes;
                    } else {
                        returnedModel = obj;
                    }

                    return returnedModel;
                },
                /**
                 * model or collection specified by path is canceled and it removes from management. delete the descendants.
                 * If the binding is not removed. If the reference may be state without properly.
                 *
                 * @memberof ModelManager
                 * @instance
                 * @param {String} path
                 * @param {Object} options @see backbone.js#Collection.remove()
                 */
                remove: function remove(path, options) {
                    var objs = this.get(path);
                    if (!objs) {
                        logger.debug('Path of unmanaged become subject to deletion, I was skipped. path:', path);
                        return this;
                    }

                    logger.debug(this.constructor.name, 'remove. path:', path);

                    if (objs.isCollection()) {
                        this._decideBindedModel(objs, true).removeAll &&
                        this._decideBindedModel(objs, true).removeAll(options);

                        this.deleteFromParent(objs);

                        return this;
                    }

                    if (objs && !_.isArray(objs)) {
                        objs = [objs];
                    }
                    // remove refference
                    _.each(this._decideBindedModel(objs), function (d) {
                        this.deleteFromParent(d);
                    }, this);

                    // dispose
                    _.each(this._decideBindedModel(objs), function (d) {
                        d.dispose && d.dispose();
                    });

                    return this;
                },

                /**
                 * Supports asynchronous communication.
                 *
                 * @memberof ModelManager
                 * @instance
                 * @param {Object} options
                 */
                ajax: function ajax(options) {
                    var method = options.type;
                    var configAjax = beez.config.ajax || {};
                    var urlRoot = beez.config.url && beez.config.url.api;
                    _.defaults(options || (options = {}), configAjax, {
                        dataType: 'json',
                        contentType: 'application/json',
                        emulateHTTP: false,
                        emulateJSON: false,
                        urlRoot: urlRoot || ''
                    });

                    if (!/^(http|https):\/\//.test(options.url)) {
                        options.url = options.urlRoot + options.url;
                    }

                    if (options.data && options.contentType &&  options.contentType.indexOf('application/json') === 0 && _.isObject(options.data)) {
                        options.data = JSON.stringify(options.data);
                    }

                    if (options.emulateJSON) {
                        options.contentType = 'application/x-www-form-urlencoded';
                    }

                    if (options.type !== 'GET' && !options.emulateJSON) {
                        options.processData = false;
                    }

                    if (options.emulateHTTP && (method === 'PUT' || method === 'DELETE' || method === 'PATCH')) {
                        options.type = 'POST';
                        if (options.emulateJSON) {
                            options.data._method = method;
                        }
                        var beforeSend = options.beforeSend;
                        options.beforeSend = function (xhr, settings) {
                            if (options.emulateHTTP && (method === 'PUT' || method === 'DELETE' || method === 'PATCH')) {
                                if (!!settings.headers) {
                                    settings.headers['X-HTTP-Method-Override'] = method;
                                } else {
                                    xhr.setRequestHeader('X-HTTP-Method-Override', method);
                                }
                            }
                            if (beforeSend) {
                                beforeSend.apply(null, arguments);
                            }
                        };
                    }

                    return $.ajax.call(null, options);
                },

                /**
                 * Supports asynchronous communication.
                 * http method: GET
                 *
                 * @memberof ModelManager
                 * @instance
                 * @param {Object} options
                 */
                $get: function (options) {
                    _.extend(options || (options = {}), { type: 'GET' });
                    return this.ajax(options);
                },

                /**
                 * Supports asynchronous communication.
                 * http method: POST
                 *
                 * @memberof ModelManager
                 * @instance
                 * @param {Object} options
                 */
                $post: function (options) {
                    _.extend(options || (options = {}), { type: 'POST' });
                    return this.ajax(options);
                },

                /**
                 * Supports asynchronous communication.
                 * http method: PUT
                 *
                 * @memberof ModelManager
                 * @instance
                 * @param {Object} options
                 */
                $put: function (options) {
                    _.extend(options || (options = {}), { type: 'PUT' });
                    return this.ajax(options);
                },

                /**
                 * Supports asynchronous communication.
                 * http method: DELETE
                 *
                 * @memberof ModelManager
                 * @instance
                 * @param {Object} options
                 */
                $delete: function (options) {
                    _.extend(options || (options = {}), { type: 'DELETE' });
                    return this.ajax(options);
                },

                /**
                 * Supports asynchronous communication.
                 * http method: PATCH
                 *
                 * @memberof ModelManager
                 * @instance
                 * @param {Object} options
                 */
                $patch: function (options) {
                    _.extend(options || (options = {}), { type: 'PATCH' });
                    return this.ajax(options);
                },

                /**
                 * Dispose self instance and models belong to.
                 *
                 * @name dispose
                 * @memberof ModelManager
                 * @instance
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');

                    var managedChildren = this.getChildrenAll(this.objs);

                    _.each(managedChildren, function (key) {
                        key.dispose();
                    });

                    delete this.urlRoot;
                    delete this._sync; // Backbone.sync

                    ModelManager.__super__.dispose.apply(this, arguments);
                }
            }
        );

        /**
         * Model Class. asynchronous
         * @class
         * @name ModelAsync
         */
        var ModelAsync = beez.Bucks.extend(
            'beez.mvcr.ModelAsync',
            {

                initialize: function initialize(model) {
                    this.model = model;
                },

                /**
                 * From the data source and retrieve data.
                 *
                 * @memberof ModelAsync
                 * @instance
                 * @see Backbone.Model#fetch
                 */
                fetch: function fetch(options) {

                    var model = this.model;
                    return this.then(function waitCb(res, next) {
                        options = options ? _.clone(options) : {};

                        options.success = function (model, res) {
                            next(null, {model: model, res: res});
                        };
                        options.error = function (model, res) {
                            next(new Error(JSON.stringify({model: model, res: res, options: options})));
                        };
                        model.fetch(options);
                    });
                },

                /**
                 * Update the data in the data source.
                 *
                 * @memberof ModelAsync
                 * @instance
                 * @see Backbone.Model#save
                 */
                save: function save(key, val, options) {
                    /* jshint eqeqeq: false, eqnull: true */
                    var attrs;

                    // Handle both `"key", value` and `{key: value}` -style arguments.
                    if (key == null || _.isObject(key)) {
                        attrs = key;
                        options = val;
                    } else if (key != null) {
                        (attrs = {})[key] = val;
                    }

                    var model = this.model;
                    return this.then(function waitCb(res, next) {

                        options = options ? _.clone(options) : {};

                        options.success = function success(model, res) {
                            next(null, {model: model, res: res});
                        };

                        options.error = function error(model, res) {
                            next(new Error(JSON.stringify({model: model, res: res, options: options})));
                        };

                        model.save(attrs, options);
                    });
                },

                /**
                 * Delete the data in the data source.
                 *
                 * @memberof ModelAsync
                 * @instance
                 * @see Backbone.Model#destroy
                 */
                destroy: function destroy(options) {

                    var model = this.model;
                    return this.then(function waitCb(res, next) {
                        options = options ? _.clone(options) : {};

                        options.success = function success(model, res) {
                            next(null, {model: model, res: res});
                        };

                        options.error = function error(model, res) {
                            next(new Error(JSON.stringify({model: model, res: res, options: options})));
                        };

                        model.destroy(options);
                    });
                },

                /**
                 * dispose this chain
                 * @memberof ModelAsync
                 * @instance
                 * @private
                 * @override
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');
                    delete this.model;
                }
            }
        );


        // -------------------
        // Model

        /**
         * Model class.
         *
         * @constructor
         * @name Model
         * @extends {Backbone.Model}
         * @see Backbone.Model
         */
        var Model = beez.extend(
            'beez.mvcr.Model',
            Base,
            Backbone.Model.prototype,
            /**
             * @lends module:beez-mvcr/model~Model.prototype
             */
            {
                /**
                 * @memberof Model
                 */
                constructor: function constructor(attribute, options, manager) {
                    var args = Array.prototype.slice.call(arguments);

                    options = options || {};
                    // data source access root url.
                    var _urlRoot = '';
                    if (options.urlRoot) {
                        _urlRoot = options.urlRoot;
                    } else if (beez.config && beez.config.url) {
                        _urlRoot = beez.config.url.api || '';
                    }
                    options.urlRoot = _urlRoot;

                    _.extend(this, _.pick(options, ['urlRoot']));

                    // Model's constructor.
                    if ((args.length === 1 && args[0].objs) ||
                        (args.length === 2 && args[1].objs) ||
                        (args.length === 3 && args[2].objs)) {
                        this.manager = args[args.length - 1];
                    }

                    if (!this.manager) {
                        logger.debug("Manager can't be managed this model.");
                    }
                    // call Backbone.constructor
                    //
                    // Warning: `Model.__supersuper__.constructor` can't use in here.
                    // Because `Backbone.Model.constructor` call `Backbone.Medel.
                    // initialize`, so call `Backbone.Model.constructor` directory.
                    Model.__super__.constructor.call(this, attribute, options);
                },

                /**
                 * call initialize method
                 *
                 * @memberof Model
                 * @name initialize
                 * @override Backbone.Model.initialize()
                 */
                initialize: function initialize() {
                    // call Backbone.Model.initialize
                    Model.__super__.initialize.apply(this, arguments);
                },
                /**
                 * Index for Model management.
                 *
                 * @memberof Model
                 * @instance
                 * @property midx
                 * @type {String}
                 */
                midx: undefined,

                /**
                 * Generating ModelAsync
                 *
                 * @memberof Model
                 * @instance
                 * @return {ModelAsync}
                 */
                async: function async() {
                    return new ModelAsync(this);
                },

                /**
                 * Collection Object?
                 * @memberof Collection
                 * @instance
                 * @return {boolean}
                 */
                isCollection: function isCollection() {
                    return false;
                },

                /**
                 * Model Object?
                 * @memberof Collection
                 * @instance
                 * @return {boolean}
                 */
                isModel: function isModel() {
                    return true;
                },

                /**
                 * Binding exists
                 *
                 * @memberof Model
                 * @instance
                 * @return {boolean}
                 */
                isBinded: function isBinded() {
                    if (this._events) {
                        var i, l, name, names, list, events;
                        names = _.keys(this._events);
                        for (i = 0, l = names.length; i < l; i++) {
                            name = names[i];
                            list = this._events[name];
                            if (list && list.length > 0) {
                                return true;
                            }
                        }
                    }
                    return false;
                },

                /**
                 * Disposes of the instance
                 *
                 * @memberof Model
                 * @instance
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');

                    delete this.manager;
                    delete this.cid;
                    delete this.attributes;
                    // delete this.url;
                    // delete this.urlRoot;
                    delete this.collection;

                    // Model.__super__.dispose.apply(this, arguments);
                },
                /**
                 * Do nothing but throw error.
                 *
                 * @name remove
                 * @function
                 * @memberof Model
                 * @instance
                 * @return Error
                 */
                remove: function remove() {
                    throw new beez.Error('Use Backbone.model.destroy() or Model.dipose() instead of this');
                }
            }
        );

        /**
         * @memberof Model
         * @function
         * @param {String} [name]
         * @param {Object} childProto
         * @borrows beez.extendThis as extend
         * @see {beez}
         * @example
         * var MyModel = Model.extend(
         *     'myapp.MyModel'
         *     {
         *         midx: 'foo',
         *         bar: function bar() {}
         *     }
         * );
         */
        Model.extend = beez.extendThis;


        // -------------------
        // CollectionAsync

        /**
         * Collection class. asynchronous
         *
         * @class
         * @name ModelAsync
         * @extends {Bucks}
         */
        var CollectionAsync = beez.Bucks.extend(
            'beez.mvcr.CollectionAsync',
            {
                initialize: function initialize(collection) {
                    this.collection = collection;
                    //_.each(Collection.__superCtor__.prototype, function(obj, idx) {});
                },
                /**
                 * New collection
                 *
                 * @memberof CollectionAsync
                 * @instance
                 * @return {Collection}
                 */
                create: function create(model, options) {
                    var self = this;
                    return this.then(function () {
                        return self.collection.create(model, options);
                    });
                },
                /**
                 * Remove collection
v                 *
                 * @memberof CollectionAsync
                 * @instance
                 * @return {Collection}
                 */
                remove: function remove(models, options) {
                    var self = this;
                    return this.then(function () {
                        return self.collection.remove(models, options);
                    });
                },
                /**
                 * @override Backbone.Collection#_reset
                 * @see Backbone.Collection#_reset
                 * @memberof CollectionAsync
                 * @instance
                 */
                _reset: function () {
                    var self = this;
                    return this.then(function () {
                        return self.collection._reset();
                    });
                },

                /**
                 * Disposes of the instance
                 *
                 * @override
                 * @memberof CollectionAsync
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');
                    delete this.collection;
                }
            }
        );


        // -------------------
        // Collection

        /**
         * Collection class.
         *
         * @constructor
         * @name Collection
         * @extends {Backbone.Collection}
         * @see Backbone.Collection
         */
        var Collection = beez.extend(
            Base,
            Backbone.Collection.prototype,
            {
                /**
                 * @memberof Collection
                 */
                constructor: function constructor(models, options, manager) {
                    /**
                     * default model
                     * @memberof Collection
                     * @type {Model}
                     */
                    if (!this.model) { this.model = Model; }

                    /**
                     * @override
                     * @memberof Collection
                     * @instance
                     */
                    this.urlRoot = (function urlRoot() {
                        var _urlRoot = '';
                        if (beez.config && beez.config.url) {
                            _urlRoot = beez.config.url.api || '';
                        }
                        return _urlRoot;
                    }());
                    // Collection's constructor.
                    this.manager = manager;
                    var newArgs = arguments;
                    if (3 <= arguments.length) {
                        newArgs = Array.prototype.slice.call(arguments, 0, arguments.length - 1);
                    }
                    Collection.__super__.constructor.apply(this, newArgs);
                },

                /**
                 * call initialize method
                 *
                 * @memberof Collection
                 * @name initialize
                 * @override Backbone.Collection.initialize()
                 */
                initialize: function initialize() {
                    // call Backbone.Collection.initialize()
                    Collection.__super__.initialize.apply(this, arguments);
                },
                /**
                 * Index for Model management.
                 *
                 * @memberof Collection
                 * @instance
                 * @property midx
                 * @type {String}
                 */
                midx: undefined,

                /**
                 * Generating Collection.
                 *
                 * @memberof Collection
                 * @instance
                 * @return {Collection}
                 */
                async: function async() {
                    return new CollectionAsync(this);
                },

                /**
                 * Collection Object?
                 * @memberof Collection
                 * @instance
                 * @return {boolean}
                 */
                isCollection: function isCollection() {
                    return true;
                },

                /**
                 * Model Object?
                 * @memberof Collection
                 * @instance
                 * @return {boolean}
                 */
                isModel: function isModel() {
                    return false;
                },

                /**
                 *
                 * @memberof Collection
                 * @override
                create: function create(model, options) {
                    options = options ? _.clone(options) : {};
                    if (!(model = this._prepareModel(model, options))) { return false; }
                    if (!options.wait) { this.add(model, options); }
                    var collection = this;
                    var success = options.success;
                    options.success = function (model, resp, options) {
                        if (options.wait) { collection.add(model, options); }
                        if (success) { success(model, resp, options); }
                    };
                    model.save(null, options);
                    return model;

                },
                 */

                /**
                 * Remove collection.
                 *
                 * @override
                 * @memberof Collection
                 * @param {Array|Object} models A Model list to delete
                 * @param {Object} options @see backbone.js#Collection.remove()
                 * @instance
                 */
                remove: function remove(models, options) {
                    // call Backbone.remove()
                    Collection.__super__.remove.apply(this, arguments);

                    models = _.isArray(models) ? models.slice() : [models];

                    _.each(models, function (m) {
                        m.dispose && m.dispose();
                    });

                    return this;
                },

                /**
                 * All the Model(s) are deleted.
                 *
                 * @memberof Collection
                 * @param {Array|Object} models A Model list to delete
                 * @param {Object} options @see backbone.js#Collection.remove()
                 * @instance
                 */
                removeAll: function removeAll(options) {
                    return this.remove(this.models, options);
                },

                /**
                 * @override
                 * @memberof Collection
                 * @instance
                 */
                _reset: function () {
                    this.length = 0;
                    _.each(this.models, function (m) {
                        m.dispose && m.dispose();
                    });
                    this.models = [];
                    this._byId  = {};
                },

                /**
                 * Binding exists
                 *
                 * @memberof Collection
                 * @instance
                 * @return {boolean}
                 */
                isBinded: function isBinded() {
                    if (this._events) {
                        var i, l, name, names, list, events;
                        names = _.keys(this._events);
                        for (i = 0, l = names.length; i < l; i++) {
                            name = names[i];
                            list = this._events[name];
                            if (list && list.length > 0) {
                                return true;
                            }
                        }
                    }
                    return false;
                },

                /**
                 * Disposes of the instance
                 * Please use remove() to perform dispose.
                 *
                 * @memberof Collection
                 * @instance
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');

                    _.each(this.models, function (m) {
                        m.dispose && m.dispose();
                    });

                    // delete this.urlRoot;
                    delete this.manager;
                    // delete this.url;
                    delete this.comparator;
                    delete this.length;
                    delete this.models;
                    delete this._byId;

                    // call Base.dispose()
                    // Collection.__super__.dispose.apply(this, arguments);
                }
            }
        );

        /**
         * @memberof Collection
         * @function
         * @param {String} [name]
         * @param {Object} childProto
         * @borrows beez.extendThis as extend
         * @see {beez}
         * @example
         * var MyCollection = Collection.extend(
         *     'myapp.MyCollection'
         *     {
         *         midx: 'foo',
         *         bar: function bar() {}
         *     }
         * );
         */
        Collection.extend = beez.extendThis;

        return {
            Model: Model,
            Collection: Collection,
            ModelManager: ModelManager,
            ModelManagerAsync: ModelManagerAsync
            //manager: modelManager
        };

    });
})(this);

/**
 * @fileOverview BeezModic
 * @name modic.js<beez-mvcr>
 * @author Go Ohtani <otani_go@cyberagent.co.jp>
 */

(function (global) {

    /**
     * BeezModic module
     * @exports beez-mvcr/modic
     */
    define('beez-mvcr/modic',['require','exports','module','beez.core','backbone','beez-mvcr/model'],function (require, exports, module) {
        

        var beez = require('beez.core');
        var _ = beez.vendor._;
        var Backbone = require('backbone');

        var model = require('beez-mvcr/model');

        /**
         * Model without data source. (Logic Model)
         *
         * @constructor
         * @name Modic
         * @extends {beez.Modic}
         */
        var Modic = model.Model.extend(
            'beez.mvcr.Modic',
            /**
             * @lends module:beez-mvcr/model~Model.prototype
             */
            {

                /**
                 * Index for Model management.
                 *
                 * @memberof Modic
                 * @instance
                 * @property midx
                 * @type {String}
                 */
                midx: undefined,


                /**
                 * @override
                 * @memberof Modic
                 * @instance
                 */
                lRoot: function urlRoot() {
                    throw new beez.Error('not allowed to use this function.');
                },

                /**
                 * @override
                 * @memberof Modic
                 * @instance
                 */
                url: function url() {
                    throw new beez.Error('not allowed to use this function.');
                },


                /**
                 * @override
                 * @memberof Modic
                 * @instance
                 * @private
                 *
                 */
                async: function async() {
                    throw new beez.Error('not allowed to use this function.');
                },

                /**
                 * @override
                 * @memberof Modic
                 * @instance
                 * @private
                 */
                fetch: function fetch(options) {
                    throw new beez.Error('not allowed to use this function.');
                },

                /**
                 * @override
                 * @memberof Modic
                 * @instance
                 * @private
                 *
                 */
                save: function save(key, val, options) {
                    throw new beez.Error('not allowed to use this function.');
                }
            }
        );

        return {
            Modic: Modic
        };
    });
})(this);

/**
 * @fileOverview View
 * @name view.js<beez-mvcr>
 * @author Kei Funagayama <funagayama_kei@cyberagent.co.jp>
 */

(function (global) {
    define('beez-mvcr/view',['require','exports','module','beez.core','backbone','beez-mvcr/base'],function __View__(require, exports, module) {
        

        var beez = require('beez.core');

        var _ = beez.vendor._;
        var Backbone = require('backbone');

        var base = require('beez-mvcr/base');
        var Base = base.Base;
        var ManagerBase = base.ManagerBase;

        var logger = beez.getLogger('beez.mvcr.view');


        /**
         * View management class, asynchronous
         *
         * @class
         * @name Creator
         * @extends {Bucks}
         */
        var ViewManagerAsync = beez.Bucks.extend(
            'beez.mvcr.ViewManagerAsync',
            {
                initialize: function initialize(manager) {
                    this.manager = manager;
                },

                /**
                 * set root
                 *
                 * @memberof ViewManagerAsync
                 * @instance
                 * @param {View} root vidx is '@' must
                 * @return {ViewManagerAsync}
                 */
                root: function root(root) {
                    var self = this;
                    return this.then(function () {
                        return self.manager.root(root);
                    });
                },

                /**
                 * Generate View.
                 *
                 * @memberof ViewManagerAsync
                 * @instance
                 * @param {String} prefix parent prefix
                 * @param {View|Array<View>} View Generate View object(s).
                 * @param {Object} [options] Argument of the View object.
                 * @return {ViewManagerAsync}
                 */
                create: function create(prefix, View, options) {
                    var self = this;
                    return this.then(function () {
                        var v =  self.manager.create(prefix, View, options);
                        var current = _.isArray(v) ? v[0] : v;
                        return current;
                    });
                },

                /**
                 * View is generated as a child of the View object generated before the chain.
                 *
                 * @memberof ViewManagerAsync
                 * @instance
                 * @param {View|Array<View>} View Generate View object.
                 * @param {Object} [options] Argument of the View object.
                 * @return {ViewManagerAsync}
                 */
                child: function child(View, options) {
                    var self = this;
                    return this.then(function (current) {
                        var prefix = self.manager.pathOf(current);
                        var v = self.manager.create(prefix, View, options);
                        current = _.isArray(v) ? v[0] : v;
                        return current;
                    });
                },

                /**
                 * Get the parent View.
                 *
                 * @memberof ViewManagerAsync
                 * @instance
                 * @return {ViewManagerAsync}
                 */
                parent: function parent() {
                    var self = this;
                    return this.then(function (current) {
                        var parent = self.manager.getParent(current);
                        if (parent) {
                            throw new beez.Error('get parent failed. current: ' + current);
                        }
                        current = parent;
                        return current;
                    });
                },

                /**
                 * The child and its brother of the parents of View.
                 *
                 * @memberof ViewManagerAsync
                 * @instance
                 * @param {object} [options] Argument of the View object.
                 * @return {Creator}
                 */
                bro: function bro(brother, options) {
                    return this.parent().child(brother, options);
                },

                /**
                 * Disposes of the instance
                 *
                 * @memberof ViewManagerAsync
                 * @override called when this chain ended
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');
                    delete this.manager;
                    delete this.current;
                    delete this.root;
                }
            }
        );

        /**
         * ViewManager Class
         *
         * @class
         * @name ViewManager
         */
        var ViewManager = beez.extend(
            'beez.mvcr.ViewManager',
            ManagerBase,
            {

                /**
                 * Constructor
                 *
                 * @memberof ViewManager
                 * @instance
                 */
                initialize: function initialize() {
                    ViewManager.__super__.initialize.apply(this, arguments);
                },

                /**
                 * Generating ViewManagerAsync
                 *
                 * @memberof ViewManager
                 * @instance
                 * @return {ViewManagerAsync}
                 */
                async: function async() {
                    return new ViewManagerAsync(this);
                },

                /**
                 * Set the Root View
                 *
                 * @memberof ViewManager
                 * @instance
                 * @param {View} RootView vidx is '@' must
                 * @return {View}
                 */
                root: function root(RootView) {
                    this.add('/', new function DummyRootView() { this.vidx = '@'; });
                    var rootView = new RootView(this);
                    var rootChildren = this.getChildren(this.get("/@")); // save
                    this.remove('/@');

                    var root = this.get('/@');
                    if (root) {
                        throw new beez.Error('root already exists!');
                    }

                    if (rootView.vidx !== '@') {
                        throw new beez.Error('roots vidx must be "@"');
                    }

                    this.add('/', rootView);

                    // re-save
                    for (var i = 0; i < rootChildren.length; i++) {
                        this.add('/@', rootChildren[i]);
                    }

                    return rootView;
                },


                /**
                 * Generate View.
                 *
                 * @memberof ViewManager
                 * @instance
                 * @param {String} prefix parent prefix
                 * @param {View|Array<View>} View Generate View object(s).
                 * @param {Object} [options] Argument of the View object.
                 * @return {Array}
                 */
                create: function create(prefix, View, options) {
                    if (!View || (!_.isArray(View) && typeof View !== 'function')) {
                        throw new beez.Error('View does not exist / does not be funciton. Specified prefix: ' + prefix);
                    }

                    if (!prefix) {
                        throw new beez.Error('No prefix specified. Creating:' + View.name);
                    }

                    if (prefix.indexOf('/@') < 0) {
                        throw new beez.Error('prefix must started by "/@". Creating:' + View.name);
                    }

                    if (!this.get(prefix)) { // no parent
                        throw new beez.Error('no parent exists. prefix: ' + prefix + ' ,  Please consider constructing view in Controller, or in #beforeOnce and so on.');
                    }


                    if (_.isArray(View)) {
                        return this._createArray(prefix, View, options);
                    }

                    return this._createObj(prefix, View, options);
                },

                /**
                 * Generate View(Object).
                 *
                 * @memberof ViewManager
                 * @instance
                 * @private
                 */
                _createObj: function _createObj(prefix, View, options) {
                    var v = new View(this, options);
                    if (!this.isAddable(v)) {
                        throw new beez.Error('index does not exists in the View. :' + v);
                    }
                    this.add(prefix, v);
                    return v;
                },


                /**
                 * Generate View(Array).
                 *
                 * @memberof ViewManager
                 * @instance
                 * @private
                 */
                _createArray: function _createArray(prefix, Views, options) {
                    var self = this;
                    // forced array
                    if (options && !_.isArray(options)) {
                        options = [options];
                    }

                    var instances = [];
                    _.each(Views, function (C, idx) {  // new
                        var params = options ? options[idx] : undefined;
                        var v = new C(self, params);
                        instances.push(v);
                    });

                    _.each(instances, function (view) { // check
                        if (!this.isAddable(view)) {
                            throw new beez.Error('index does not exists in the View. :' + view);
                        }
                    }, this);

                    this.add(prefix, instances);
                    return instances;
                },

                /**
                 * remove
                 *
                 * @name remove
                 * @memberof ViewManager
                 * @instance
                 * @param {String} path
                 */
                remove: function remove(path) {
                    ViewManager.__super__.remove.apply(this, arguments);
                },

                /**
                 * Dispose view and self from management.
                 *
                 * @memberof ViewManager
                 * @instance
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');

                    var managedChildren = this.getChildrenAll(this.objs);

                    _.each(managedChildren, function (key) {
                        key.dispose();
                    });

                    ViewManager.__super__.dispose.apply(this, arguments);
                }
            }
        );

        // -------------------
        // View

        /**
         * View class Asynchronous
         *
         * @class
         * @name ViewAsync
         * @extends {Bucks}
         * @private
         */
        var ViewAsync = beez.Bucks.extend(
            'beez.mvcr.ViewAsync',
            {

                /**
                 * @memberof ViewAsync
                 * @param {View} root Root View
                 */
                initialize: function initialize(root) {
                    this._root = root;
                },

                /**
                 * Processing is performed by the flow of [beforeOnce -> before -> render -> after -> afterOnce].
                 *
                 * @memberof Renderer
                 * @instance
                 * @param {BeezView} view
                 * @param {boolen} [renderChildren=true]
                 */
                _render: function _render(view) {

                    // start with view
                    this.then(function () {
                        return view;
                    });

                    if (!view.state.isBeforeOnce) { // check flag
                        // call beforeOnce
                        this.then(function beforeOnce(view, next) {
                            if (!view.visible) {
                                logger.debug('view', view.vidx, 'is not visible. skip `beforeOnce`.');
                                next(null, view); // skip
                                return;
                            }

                            // if `beforeOnce` have `done` as a param
                            if (view.beforeOnce.length) {
                                view.beforeOnce(function wrappedDone() {
                                    view.state.isBeforeOnce = true;
                                    next(null, view);
                                });
                                return;
                            }

                            // else exec as sync
                            view.beforeOnce();
                            view.state.isBeforeOnce = true;
                            next(null, view);
                        });
                    }


                    // call before
                    this.then(function before(view, next) {
                        if (!view.visible) {
                            logger.debug('view', view.vidx, 'is not visible. skip `before`.');
                            next(null, view); // skip
                            return;
                        }

                        // if `before` have `done` as a param
                        if (view.before.length) {
                            view.before(function wrappedDone() {
                                next(null, view);
                            });
                            return;
                        }
                        // else exec as sync
                        view.before();
                        next(null, view);

                    });


                    // call render
                    this.then(function render(view, next) {
                        if (!view.visible) {
                            logger.debug('view', view.vidx, 'is not visible. skip `render`.');
                            next(null, view); // skil
                            return;
                        }

                        // if `render` have `done` as a param
                        if (view.render.length) {
                            view.render(function wrappedDone() {
                                next(null, view);
                            });
                            return;
                        }

                        // else exec as sync
                        view.render();
                        next(null, view);
                        return;
                    });

                    // call after
                    this.then(function after(view, next) {
                        if (!view.visible) {
                            logger.debug('view', view.vidx, 'is not visible. skip `after`.');
                            next(null, view); // skip
                            return;
                        }

                        // if `afterOnce` have `done` as a param
                        if (view.after.length) {
                            view.after(function wrappedDone() {
                                next(null, view);
                            });
                            return;
                        }

                        // else exec as sync
                        view.after();
                        next(null, view);
                        return;
                    });

                    if (!view.state.isAfterOnce) { // check flag

                        // call afterOnce
                        this.then(function afterOnce(view, next) {
                            if (!view.visible) {
                                logger.debug('view', view.vidx, 'is not visible. skip `afterOnce`.');
                                next(null, view); // skip
                                return;
                            }

                            // if `afterOnce` have `done` as a param
                            if (view.afterOnce.length) {
                                view.afterOnce(function wrappedDone() {
                                    view.state.isAfterOnce = true;
                                    next(null, view);
                                });

                                return;
                            }

                            // else exec as sync
                            view.afterOnce();
                            view.state.isAfterOnce = true;
                            next(null, view);
                            return;
                        });
                    }

                    return this;
                },


                /**
                 * Delete the View.
                 *
                 * @memberof ViewAsync
                 * @instance
                 * @param {View} view
                 * @return {View}
                 */
                _remove: function _remove(view) {

                    return this.then(function () {
                        view.remove();
                        return view;
                    });
                },


                /**
                 * Handles the rendering of the View.
                 * Child elements are rendered.
                 *
                 * visible=false : Skip the rendering, including the child elements.
                 * showChildren=false : Only the specified view is rendered, child elements are not rendered.
                 *
                 * @memberof ViewAsync
                 * @instance
                 * @public
                 * @param {boolean} [showChildren=false] if not show children, set false
                 * @return {ViewAsync}
                 * @throws {beez.Error} render root is not set
                 */
                show: function show(showChildren) {
                    if (!this._root) {
                        throw new beez.Error('render root is not set. initialize renderer with root view parameter.');
                    }
                    return this._show(this._root, showChildren);
                },


                /**
                 * Handles the rendering of the View.
                 * Child elements are rendered.
                 *
                 * visible=false : Skip the rendering, including the child elements.
                 * showChildren=false : Only the specified view is rendered, child elements are not rendered.
                 *
                 *
                 * @memberof ViewAsync
                 * @instance
                 * @private
                 * @param {View} view view to show
                 * @param {boolean} [showChildren=false] if not show children, set false
                 * @return {ViewAsync}
                 */
                _show: function _show(view, showChildren) {

                    if (showChildren === undefined) {
                        showChildren = true;
                    }

                    var self = this;
                    if (!_.isArray(view)) {
                        logger.debug('showing', view.vidx);
                        this._render(view, showChildren); // case of single view
                    } else {
                        if (_.isEmpty(view)) { return this; }

                        // sort order property
                        view.sort(function (a, b) {
                            if (a.order < b.order) {
                                return -1;
                            }
                            if (a.order > b.order) {
                                return 1;
                            }

                            return 0;
                        });

                        // create render tasks
                        var tasks = _.map(
                            view,
                            function makeTask(v) {
                                return function task(err, res, next) {
                                    if (err) { throw err; }
                                    new ViewAsync()
                                        ._show(v, showChildren)
                                        .end(function (e, r) {
                                            next(e, undefined);
                                        });
                                };
                            }
                        );
                        this.waterfall(tasks);

                    }

                    if (showChildren) {
                        this.then(function renderC(view, next) {
                            if (!view) { return next(null, view); }

                            var children = view.getChildren();
                            if (_.isEmpty(children)) {
                                return next(null, view);
                            } else {
                                return new ViewAsync()
                                    ._show(children, showChildren)
                                    .end(next);
                            }
                        });
                    }

                    return this;
                },


                /**
                 * Handles the rendering of the View.
                 * Child elements are rendered.
                 *
                 * want to hide the View. And hide also to the child element
                 * hideChildren=false: Child element is not hidden.
                 *
                 * @memberof ViewAsync
                 * @instance
                 * @private
                 * @param {View} view view to hide
                 * @param {boolean} [hideChildren=true] if set false, children not be removed
                 * @return {ViewAsync}
                 */
                hide: function hide(hideChildren) {
                    if (!this._root) {
                        throw new beez.Error('render root is not set. initialize renderer with root view parameter.');
                    }
                    return this._hide(this._root, hideChildren);
                },


                /**
                 * Handles the rendering of the View.
                 * Child elements are rendered.
                 *
                 * want to hide the View. And hide also to the child element
                 * hideChildren=false: Child element is not hidden.
                 *
                 * @memberof ViewAsync
                 * @instance
                 * @private
                 * @param {View} view view to hide
                 * @param {boolean} [hideChildren=true] if set false, children not be removed
                 * @return {ViewAsync}
                 */
                _hide: function _hide(view, hideChildren) {

                    if (hideChildren === undefined) {
                        hideChildren = true;
                    }

                    var self = this;
                    if (!_.isArray(view)) { // case of single view
                        logger.debug('hiding', view.vidx);
                        this._remove(view);

                    } else { // create render tasks
                        var tasks = _.map(
                            view,
                            function makeTask(v) {
                                return function task(err, res, next) {
                                    if (err) { throw err; }
                                    new ViewAsync()
                                        ._hide(v, hideChildren)
                                        .end(function (err, ress) {
                                            next(err, undefined);
                                        });
                                };
                            }
                        );
                        this.waterfall(tasks);
                    }

                    if (hideChildren) {
                        this.then(function hideC(view, next) {
                            if (!view) { return next(null, view); }
                            var children = view.getChildren();
                            if (_.isEmpty(children)) {
                                return next(null, view);
                            } else {
                                return new ViewAsync()
                                    ._hide(children, hideChildren)
                                    .end(next);
                            }
                        });
                    }

                    return this;
                },

                /**
                 * Disposes of the instance
                 *
                 * @memberof ViewAsync
                 * @instance
                 */
                dispose: function dispopse() {
                    logger.trace(this.constructor.name, 'dispose');
                    delete this._root;
                }

            }
        );

        /**
         * View class
         *
         * @namespace beez.mvcr
         * @class
         * @name View
         * @extends {Backbone.View}
         * @see Backbone.View
         */
        var View = beez.extend(
            'beez.mvcr.View',
            Base,
            Backbone.View.prototype,
            {

                /**
                 * Constructor
                 *
                 * @memberof View
                 */
                constructor: function constructor() {
                    if (arguments.length < 1) {
                        throw new beez.Error('In order to create a View, requires one arguments.');
                    }
                    this.manager = arguments[0];

                    /**
                     * Management flag
                     * @memberof View
                     */
                    this.state = {
                        isBeforeOnce: false,
                        isAfterOnce: false
                    };

                    /**
                     * Skip rendering flag
                     *
                     * @memberof View
                     * @instance
                     * @property visible
                     * @type {boolean}
                     */
                    this.visible = true;

                    View.__super__.constructor.apply(this, Array.prototype.slice.call(arguments, 1));
                },

                /**
                 * call initialize method
                 *
                 * @memberof View
                 * @name initialize
                 * @override Backbone.View.initialize()
                 */
                initialize: function initialize() {
                    // call Backbone.View.initialize()
                    View.__super__.initialize.apply(this, arguments);
                },
                /**
                 * Index for View management.
                 *
                 * @memberof View
                 * @instance
                 * @property vidx
                 */
                vidx: undefined, // View Index key

                /**
                 * HTMLElement
                 * @see Backbone#View
                 *
                 * @memberof View
                 * @instance
                 * @property el
                 */
                el: undefined,

                /**
                 * The order from the parent View
                 *
                 * @memberof View
                 * @instance
                 * @property order
                 */
                order: 0,

                /**
                 * The function performed before render is performed when a show function is performed. (only once)
                 * Until next runs to waiting after that function, to define a next as an argument, to delay the process.
                 *
                 * @memberof View
                 * @instance
                 * @function
                 * @param {Function} [next]
                 * @example
                 * beforeOnce: function beforeOnce(next) {
                 *     somethingAsync(function() {
                 *         next();
                 *     });
                 * }
                 *
                 */
                beforeOnce: beez.none,


                /**
                 * The function performed before render is performed when a show function is performed.
                 * Until next runs to waiting after that function, to define a next as an argument, to delay the process.
                 *
                 * @memberof View
                 * @instance
                 * @function
                 * @param {Function} [next]
                 * @example
                 * before: function before(next) {
                 *     somethingAsync(function() {
                 *         next();
                 *     });
                 * }
                 */
                before: beez.none,


                /**
                 * Execute after this view have been rendered.
                 * You can delay processes to give `next` in arugument, then processes made to be delayed untill for call `next`.
                 *
                 * @memberof View
                 * @instance
                 * @function
                 * @param {Function} [next]
                 * @example
                 * after: function after(next) {
                 *     somethingAsync(function() {
                 *         next();
                 *     });
                 * }
                 */
                after: beez.none,


                /**
                 * Execute once after this view have been rendered.
                 * You can delay processes to give `next` in arugument, then processes made to be delayed untill for call `next`.
                 *
                 * @memberof View
                 * @instance
                 * @function
                 * @param {Function} [next]
                 * @example
                 * afterOnce: function afterOnce(next) {
                 *     somethingAsync(function() {
                 *         next();
                 *     });
                 * }
                 */
                afterOnce: beez.none,

                /**
                 * Generate async class
                 *
                 * @memberof View
                 * @instance
                 * @return {ViewAsync}
                 */
                async: function async() {
                    return new ViewAsync(this);
                },

                /**
                 * Return existence of HTMLElement on DOM tree in this view.
                 *
                 * @memberof View
                 * @instance
                 * @function
                 * @return {boolean}
                 */
                isRendered: function isRendered() {
                    return !!this.el && !!this.el.parentElement;
                },

                /**
                 * set visible
                 *
                 * @memberof View
                 *
                 * @param {boolean} visible
                 * @throw {Error} typeof visible invalid. should be boolean
                 * @return {View} this
                 */
                setVisible: function setVisible(visible) {
                    if (typeof visible !== 'boolean') {
                        throw beez.Error('typeof visible invalid. should be boolean.');
                    }
                    this.visible = visible;
                    return this;
                },


                /**
                 * Disposes of the instance and remove HTMLElement
                 * and undelegate event on all view.
                 *
                 * @memberof View
                 * @instance
                 * @override Backbone.View.undelegateEvents
                 * @return
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');

                    this.remove();

                    // call Backbone.undelegateEvents method
                    View.__super__.undelegateEvents.apply(this, arguments);

                    delete this.manager;
                    delete this.state;
                    delete this.visible;
                    delete this.cid;
                    delete this.options;
                    delete this.$el;
                    delete this.model;
                    delete this.collection;
                    delete this.el;
                    // delete this.id;
                    delete this.attributes;
                    delete this.className;
                    delete this.tagName;
                    // delete this.events;

                    // call Base.dispose()
                    // View.__super__.dispose.call(this);
                },
                /**
                 * Remove HTMLElement.
                 *
                 * @memberof View
                 * @function
                 * @override Backbone.View.remove
                 * @return
                 */
                remove: function remove() {
                    // call Backbone.remove
                    View.__super__.remove.apply(this, arguments);
                }
            }
        );


        /**
         * @memberof View
         * @function
         * @param {String} [name]
         * @param {Object} childProto
         * @borrows beez.extendThis as extend
         * @example
         * var MyView = View.extend(
         *     'myapp.MyView',
         *     {
         *         vidx: 'foo',
         *         bar: function bar() {}
         *     }
         * );
         */
        View.extend = beez.extendThis;

        return {
            View: View,
            ViewAsync: ViewAsync,
            ViewManager: ViewManager,
            ViewManagerAsync: ViewManagerAsync
        };
    });
})(this);

/**
 * @fileOverview Controller/ControllerManager
 * @name controller.js<beez-mvcr>
 * @author Kei Funagayama <funagayama_kei@cyberagent.co.jp>
 */

(function (global) {

    define('beez-mvcr/controller',['require','exports','module','beez.core','beez.mvcr','beez.i18n'],function __Controller__(require, exports, module) {
        

        var beez = require('beez.core');
        require('beez.mvcr');
        require('beez.i18n');

        var logger = beez.getLogger('beez.mvcr.controller');

        var _ = beez.vendor._;

        // -------------------
        // ControllerManagerAsync

        /**
         * Controller management class, asynchronous
         *
         * @class
         * @name ControllerManagerAsync
         * @private
         * @param {ControllerManager} manager
         * @extends {Bucks}
         */
        var ControllerManagerAsync = beez.Bucks.extend(
            'beez.mvcr.ControllerManagerAsync',
            {
                /**
                 * Constructor
                 *
                 * @memberof ControllerManagerAsync
                 * @instance
                 */
                initialize: function initialize(manager) {
                    this.manager = manager;
                },

                /**
                 * Generation of the Controller
                 *
                 * @memberof ControllerManagerAsync
                 * @instance
                 * @param {String} prefix
                 * @param {Controller|Array<Controller>} Controller Controller Object
                 * @param {Object|Array<Object>} [options] Arguments to the Controller
                 * @return {Controller}
                 */
                create: function create(name, Controller, options) {
                    var self = this;
                    return this.then(function createWrap(result, next) {

                        if (!Controller || typeof Controller !== 'function') {
                            throw new beez.Error('Controller does not exist / does not be funciton. Specified name: ' + name);
                        }
                        if (self.manager.controllers[name]) {
                            throw new beez.Error('It is a singleton in the module. name:' + name);
                        }

                        var controller = new Controller();
                        self.manager.controllers[name] = controller;
                        next(result, self.manager.controllers[name]);

                    }).then(function (controller, next) {
                        controller.loadCSS(function () { // initialize css load
                            next(null, controller);
                        });

                    }).then(function (controller, next) {
                        controller.loadI18n(function (err) { // initialize i18n load
                            if (err) {
                                logger.error('i18n load error. ', err.message);
                                logger.debug(err.stack);
                            }
                            next(err, controller);
                        });
                    });
                },

                /**
                 * Disposes of the instance
                 *
                 * @memberof ControllerManagerAsync
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');
                    delete this.manager;
                }
            }
        );

        // -------------------
        // ControllerManager

        /**
         * Controller management class.
         *
         * @class
         * @name ControllerManager
         */
        var ControllerManager = beez.extend(
            'beez.mvcr.ControllerManager',
            function constructor() {
                return this.initialize();
            },
            {
                /**
                 * Constructor
                 *
                 * @memberof ControllerManager
                 * @instance
                 */
                initialize: function initialize() {
                    this.controllers = {};
                },

                /**
                 * Generating ControllerManagerAsync
                 *
                 * @memberof ControllerManager
                 * @instance
                 * @return {ControllerAsync}
                 */
                async: function async() {
                    return new ControllerManagerAsync(this);
                },

                /**
                 * Remove controller
                 *
                 * @memberof ControllerManager
                 * @instance
                 * @param {String} name jsonPath name
                 * @return {ControllerManager}
                 */
                remove: function remove(name) {
                    var obj = this.get(name);
                    if (!obj) {
                        return this;
                    }
                    delete this.controllers[name];
                    return this;
                },

                /**
                 * From path, acquire Controller.
                 *
                 * @memberof ControllerManager
                 * @instance
                 * @param {String} name jsonPath name
                 * @return {Controller}
                 */
                get: function get(name) {
                    return this.controllers[name];
                },

                /**
                 * Disposes of the instance
                 *
                 * @memberof ControllerManager
                 * @instance
                 */
                dispose: function () {
                    logger.trace(this.constructor.name, 'dispose');
                    delete this.controllers;
                }
            });


        // -------------------
        // Controller

        /**
         * Controller class.
         *
         * @namespace beez.mvcr
         * @class
         * @name Controller
         */
        var Controller = beez.extend(
            'beez.mvcr.Controller',
            function constructor() {
                this.initialize.apply(this, arguments);
            },
            {

                /**
                 * Constructor
                 *
                 * @memberof Controller
                 * @instance
                 */
                initialize: function initialize() {
                },

                /**
                 * automatic loading of i18n data.
                 * @memberof Controller
                 * @param {function} callback
                 */
                i18n: function i18n() {},

                /**
                 * automatic loading of i18n.
                 *
                 * @memberof Controller
                 * @param {function} callback Completion callback
                 * @instance
                 * @return {Controller}
                 */
                loadI18n: function loadI18n(callback) {
                    if (!beez.i18n) {
                        beez.createI18n();
                    }

                    var self = this;
                    if (beez.utils.is('Object', this.i18n)) { // dynamic load

                        var langs = [];
                        var paths = [];
                        _.each(this.i18n, function (path, lang) {
                            langs.push(lang);
                            paths.push(path);
                        });

                        require(paths, function () {
                            var list = Array.prototype.slice.call(arguments);
                            for (var i = 0; i < list.length; i++) {
                                var data = {};
                                data[langs[i]] = list[i];
                                beez.i18n.add(data);
                                logger.debug('i18n file loaded. path:', paths[i]);
                            }
                            callback && callback(null);
                        }, function (err) {
                            callback && callback(err);
                        });

                    } else if (beez.utils.is('Function', this.i18n)) { // static load
                        new beez.Bucks()
                            .add(function (err, res, next) {
                                if (0 < self.i18n.length) {
                                    self.i18n(function (err, res) {
                                        next(err, res);
                                    });
                                } else {
                                    next(null, self.i18n());
                                }
                            })
                            .add(function (err, res) {
                                if (res) {
                                    beez.i18n.add(res);
                                }
                                callback && callback(err, res);
                            })
                            .end();

                    } else {
                        callback && callback(new Error('The Controller.i18n, please be defined in Function.'));
                    }
                    return this;

                },

                /**
                 * automatic loading of css.
                 *
                 * @memberof Controller
                 * @param {function} callback Completion callback
                 * @instance
                 * @return {Controller}
                 */
                loadCSS: function loadCSS(callback) {
                    var paths = this.css;
                    if (!paths || paths.length < 1) {
                        return callback && callback();
                    }

                    var self = this;
                    var tasks = _.map(paths, function task(p) {
                        return function t(err, res, next) {
                            beez.manager.css.async()
                                .load(p)
                                .end(function (err1, res1) {
                                    next(err, res1[0]);
                                }, function (err2) {
                                    next(err2);
                                });
                        };
                    });

                    var b = new beez.Bucks();
                    b.parallel(tasks)
                        .end(function (err, ress) {
                            callback && callback(err, ress);
                        });

                    return this;
                },

                /**
                 * Disposes of the instance
                 *
                 * @memberof Controller
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');
                    delete this.constructor.prototype.css;
                }
            }
        );


        /**
         * extend function
         *
         * @memberof Controller
         * @function
         * @param {String} [name] instance name
         * @param {Object} childProto prototypes
         * @borrows beez.extendThis as extend
         * @example
         * var MyController = Controller.extend(
         *     'myapp.MyController',
         *     {
         *         bar: function bar() {}
         *     }
         * );
         */
        Controller.extend = beez.extendThis;

        return {
            Controller: Controller,
            ControllerManager: ControllerManager,
            ControllerManagerAsync: ControllerManagerAsync
        };
    });
})(this);

/**
 * @fileOverview Router
 * @name router.js<beez-mvcr>
 * @author Kei Funagayama <funagayama_kei@cyberagnet.co.jp>
 */

(function (global) {
    define('beez-mvcr/router',['require','exports','module','beez.core','beez.mvcr','backbone'],function (require, exports, module) {
        

        var beez = require('beez.core');
        require('beez.mvcr');

        var logger = beez.getLogger('beez.mvcr.router');

        var _ = beez.vendor._;
        var Backbone = require('backbone');

        var __RouterManager__ = {


            initialize: function initialize() {

                /**
                 * Router instance (singleton)
                 *
                 * @memberof RouterManager
                 * @instance
                 */
                this.router = undefined;

                /**
                 * Router setup is complete
                 *
                 * @memberof RouterManager
                 * @instance
                 */
                this.setuped = false;
            },

            /**
             * router is initialized and routing is setuped.
             *
             * @memberof RouterManager
             * @instance
             * @param {Object} [options] overwrite merge the routes pass the set of routes
             * @param {beez.Router} [Router] Expanded Router instance.
             */
            setup: function setup(options, router) {
                var self = this;

                /* jshint loopfunc: true */
                if (this.setuped) {
                    throw new beez.Error('Already been executed once. If you want to add a route, please refer to the function add().');
                }

                var config = beez.config.router || {};
                var routes = _.extend(config, options); // merge

                //logger.debug("router.setup", JSON.stringify(routes));

                if (this.router) {
                    return this;
                }

                // router extend or create
                this.router = router || new beez.Router();

                // register routes
                var names = _.keys(routes);
                for (var i = 0; i < names.length; i++) {
                    var key = names[i];
                    var data = routes[key];

                    //logger.debug('router.route', key, JSON.stringify(data));

                    this.router.route(data.route, data.name, (function (name) {
                        function proxy() {

                            if (!routes.hasOwnProperty(name)) {
                                throw new beez.Error('route map key does not exist. name: ' + name);
                            }
                            var data = routes[name];
                            //var parameter = arguments;
                            var parameter = Array.prototype.slice.call(arguments);


                            logger.debug("router.proxy", data);


                            var job = new beez.Bucks();

                            job.then(function (res, next) {
                                if (beez.manager.c.get(data.xpath)) { // Already controller loaded
                                    return next();
                                }

                                // First controller load function
                                if (data.async) { // Asynchronous

                                    if (self.router.firstBefore.length !== 2) {
                                        throw new beez.Error('You should pass a callback function in arguments in case of async setting is true. firestBefore(data, callback)');
                                    }

                                    logger.trace("run controller firstBefore function(async). data:", data);
                                    self.router.firstBefore(data, function (err, res) {
                                        next(null, res);
                                    });

                                } else { // Synchronism
                                    logger.trace("run controller firstBefore function(sync). data:", data);
                                    self.router.firstBefore(data);
                                    next();
                                }
                            });

                            job.then(function (res, next) {
                                require([data.require], function cnavigate(_Controller) {

                                    logger.debug("controller.exec", data.xpath);
                                    var _controller = beez.manager.c.get(data.xpath);

                                    var state = {};
                                    if (_controller) {
                                        state.isFirstBefore = true;
                                        next(null, {Controller: _Controller, controller: _controller, state: state});
                                        return;
                                    }
                                    beez.manager.c.async().create(data.xpath, _Controller).then(function (_controller) {
                                        state.isFirstBefore = false;
                                        next(null, {Controller: _Controller, controller: _controller, state: state});
                                    }).end();
                                });
                            });

                            job.then(function (res, next) {
                                var controller = res.controller;
                                var Controller = res.Controller;
                                // set state
                                data.state = res.state;

                                if (!controller[data.name]) {
                                    throw new beez.Error('"' + data.name + '" to Controller I is undefined.');
                                }
                                if (data.async) {

                                    if (self.router.before.length !== 3) {
                                        throw new beez.Error('You should pass a callback function in arguments in case of async setting is true. before(data, Controller, callback)');
                                    }

                                    logger.trace("run controller before function(async). data:", data);
                                    self.router.before(data, Controller, function (err, res) { // run before function

                                        parameter.push(function (err, res) { // set after callback
                                            if (self.router.after.length !== 3) {
                                                throw new beez.Error('You should pass a callback function in arguments in case of async setting is true. after(data, Controller, callback)');
                                            }

                                            logger.trace("run controller after function(async). data:", data);
                                            self.router.after(data, Controller, function (err, res) { // run after function
                                                next();
                                            });
                                        });

                                        if (controller[data.name].length !== parameter.length) {
                                            throw new beez.Error('"Controller.' + data.name + '" function should takes ' + parameter.length + ' arguments. (' + controller[data.name].length + ')');
                                        }
                                        controller[data.name].apply(controller, parameter);
                                    });

                                } else {

                                    logger.trace("run controller before function(sync). data:", data);
                                    self.router.before(data, Controller); // run before function

                                    controller[data.name].apply(controller, parameter); // exec!!

                                    logger.trace("run controller after function(sync). data:", data);
                                    self.router.after(data, Controller); // run after function

                                    next();
                                }
                            });

                            job.end(); // fire!!!


                            /**
                            // processing of controller before loading.
                            if (!beez.manager.c.get(data.xpath)) {
                                logger.trace("run controller firstBefore function. data:", data);
                                self.router.firstBefore(data);
                            }

                            require([data.require], function cnavigate(_Controller) {

                                logger.debug("controller.exec", data.xpath);
                                var controller = beez.manager.c.get(data.xpath);
                                if (controller) {
                                    if (!controller[data.name]) {
                                        throw new beez.Error('"' + data.name + '" to Controller I is undefined.');
                                    }

                                    logger.trace("run controller before function. data:", data);
                                    self.router.before(data, _Controller); // run before function

                                    controller[data.name].apply(controller, parameter); // exec!!

                                    logger.trace("run controller after function. data:", data);
                                    self.router.after(data, _Controller); // run after function

                                } else {
                                    beez.manager.c.async().create(data.xpath, _Controller).then(function (controller) {
                                        if (!controller[data.name]) {
                                            throw new beez.Error('"' + data.name + '" to Controller I is undefined.');
                                        }

                                        logger.trace("run controller before function. data:", data);
                                        self.router.before(data, _Controller); // run before function

                                        controller[data.name].apply(controller, parameter); // exec!!

                                        logger.trace("run controller after function. data:", data);
                                        self.router.after(data, _Controller); // run after function

                                    }).end();
                                }
                            });
                            */
                        }


                        return proxy;

                    })(key));
                }
                this.setuped = true;
            },

            /**
             * @see Backbone#Router.navigate
             *
             * @memberof RouterManager
             * @instance
             * @see Router
             */
            navigate: function navigate(fragment, options) {
                if (!this.setuped || !this.router) {
                    throw new beez.Error(
                        'Initialization has not been performed even once. Please do a "setup()".');
                }
                return this.router.navigate(fragment, options);
            },

            /**
             * Dispose self instance
             *
             * @name dispose
             * @memberof RouterManager
             * @instance
             */
            dispose: function dispse() {
                logger.trace(this.constructor.name, 'dispose');
                this.router && this.router.dispose && this.router.dispose();
                delete this.router;
                delete this.setuped;
            }
        };

        /**
         * Routing management class.
         *
         * @class
         * @name RouterManager
         */
        var RouterManager = beez.extend(
            'beez.mvcr.RouterManager',
            function constructor() {
                return this.initialize();
            }, __RouterManager__);


        /**
         * Router Class (singleton)
         * @class
         * @name Router
         * @extends {Backbone.Router}
         * @see Backbone.Router
         */
        var Router = beez.extend(
            'beez.mvcr.Router',
            Backbone.Router,
            {

                /**
                 * @memberof Router
                 */
                constructor: function constructor() {
                    Router.__super__.constructor.apply(this, arguments);
                },

                /**
                 * Constructor
                 *
                 * @memberof Router
                 * @instance
                 */
                initialize: function initialize() {
                    Router.__super__.initialize.apply(this, arguments);
                },

                /**
                 * Interrupt processing of execution first before the controller.
                 *
                 * @memberof Router
                 * @param {Object} data Router information of the target.
                 * @instance
                 */
                firstBefore: function firstBefore(data, next) {
                    if (next) {
                        next();
                    }
                },
                /**
                 * Interrupt processing of execution before the controller.
                 *
                 * @memberof Router
                 * @param {Object} data Router information of the target.
                 * @param {Controller} Controller Controller class of target
                 * @instance
                 */
                before: function before(data, Controller, next) {
                    if (next) {
                        next();
                    }
                },

                /**
                 * Interrupt processing of execution after the controller.
                 *
                 * @memberof Router
                 * @param {Object} data Router information of the target.
                 * @param {Controller} Controller Controller class of target
                 * @instance
                 */
                after: function after(data, Controller, next) {
                    if (next) {
                        next();
                    }
                },

                /**
                 * Dispose self instance
                 *
                 * @name dispose
                 * @memberof Router
                 * @instance
                 */
                dispose: function dispse() {
                    logger.trace(this.constructor.name, 'dispose');
                }
            }
        );

        /**
         * @memberof Router
         * @function
         * @param {String} [name]
         * @param {Object} childProto
         * @borrows beez.extendThis as extend
         * @example
         * var MyRouter = beez.Router.extend(
         *     'myapp.MyRouter',
         *     {
         *     }
         * );
         */
        Router.extend = beez.extendThis;

        return {
            Router: Router,
            RouterManager: RouterManager
        };
    });
})(this);

/**
 * @fileOverview CSSManager
 * @name cssmanager.js<beez-mvcr>
 * @author Kei Funagayama <funagayama_kei@cyberagent.co.jp>
 */

(function (global) {

    define('beez-mvcr/cssmanager',['require','exports','module','beez.core'],function (require, exports, module) {
        

        var beez = require('beez.core');
        var logger = beez.getLogger('beez.mvcr.cssmanager');

        var _ = beez.vendor._;
        var $ = beez.vendor.$;

        // -------------------
        // functions

        /**
         * @see CSSManager.isExists
         */
        var isExists = function isExists(path) {
            var stylesheets = document.styleSheets;
            var found = _.find(stylesheets, function (sheet) {
                var href = sheet.href;
                return (href && href.indexOf(path) !== -1);
            });
            return found && found.rules && found.rules.length > 0;
        };

        /**
         * @see CSSManager.isLoaded
         */
        var isLoaded = function isLoaded(path) {
            var stylesheets = document.styleSheets;

            var found = _.find(stylesheets, function (sheet) {
                var href = sheet.href;
                return (href && href.indexOf(path) !== -1);
            });
            return !!found;
        };

        // -------------------
        // CSSManagerAsync

        /**
         * Load the CSS with the given path, and then run the callback in the timing that have been added to the document.styleSheets. (asynchronous)
         *
         * @class
         * @name CSSManagerAsync
         * @private
         * @param {CSSManager} manager
         * @extends {Bucks}
         *
         * @example
         * var async = new CSSManagerAsync('/index.css');
         * async.then(function() {
         *     // succesfully loaded
         * }).error(function err() {
         *     // error on loading
         * }).end();
         *
         */
        var CSSManagerAsync = beez.Bucks.extend(
            'beez.mvcr.CSSManagerAsync',
            {

                initialize: function initialize(manager) {
                    this.manager = manager;
                    this._path = '';
                    this._intervalId = undefined;
                    this._timeoutId = undefined;

                    // load-checking interval
                    this.INTERVAL = (
                        (beez.config.manager &&
                         beez.config.manager.css &&
                         beez.config.manager.css.interval) || 1000 / 20
                    );

                    // load-timeout
                    this.TIMEOUT = (
                        (beez.config.manager &&
                         beez.config.manager.css &&
                         beez.config.manager.css.timeout) || 1000 * 10
                    );
                },

                /**
                 * CSS is loaded.
                 * Warnnig: The present condition and the unific method of detecting HTTP Response Code (404, ...) are not found.
                 * When http or https is in a head, it loads by name directly.
                 *
                 * @memberof CSSManagerAsync
                 * @instance
                 * @asynchronous
                 *
                 * @example
                 * CSSManager.load('/index.css')
                 * .error(function onError() {
                 * // timeout etc
                 * })
                 * .then(function then() {
                 * })
                 * .end();
                 */
                load: function load(name) {
                    var self = this;

                    var path = this._path = name;
                    if (!name.match(/^(http|https):\/\/.+$/)) {
                        path = this._path = this.manager.name2path(name);
                    }

                    if (!path) {
                        return this.empty(); // ignore
                    }

                    if (this.manager.isLoaded(path)) {
                        logger.debug('path:', path, 'already exists');
                        path = undefined;
                        return this.empty(); // ignore
                    }

                    // insert link tag for stylesheet
                    var linkstyleTag = '<link rel="stylesheet" href="' + _.escape(path) + '" ></link>';
                    $('head').append(linkstyleTag);

                    return this.then(function loadWrap(res, next) {

                        self._intervalId = setInterval(function () { // TODO: utils#timer replace
                            if (isLoaded(path)) { //stylesheetが存在
                                self.abort(); //ruleが存在
                                logger.debug('load finished. path:', path);
                                next();
                            }
                        }, self.INTERVAL);

                        self._timeoutId = setTimeout(function () { // TODO: utils#timer replace
                            self.abort();
                            next(new beez.Error('loading timed out. path:' + path));
                        }, self.TIMEOUT);
                    });
                },

                /**
                 * remove the link tag in the path contained in the name.
                 *
                 * @asynchronous
                 * @memberof CSSManagerAsync
                 * @insntace
                 *c @param {String} name
                 */
                remove: function remove(name) {
                    var self = this;
                    return this.then(function remove() {
                        return self.manager.remove(name);
                    });
                },

                /**
                 * Cancel the monitor.
                 *
                 * @instance
                 * @memberof CSSManagerAsync
                 */
                abort: function abort() {
                    clearTimeout(this._timeoutId);
                    clearInterval(this._intervalId);
                    delete this._timeoutId;
                    delete this._intervalId;
                    delete this.INTERVAL;
                    delete this.TIMEOUT;
                },

                /**
                 * Disposes of the instance
                 *
                 * @instance
                 * @memberof CSSManagerAsync
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');
                    delete this.manager;
                    delete this._path;
                    this.abort();
                }
            }
        );

        // -------------------
        // CSSManager

        /**
         * Load the CSS with the given path, and then run the callback in the timing that have been added to the document.styleSheets. (asynchronous)
         *
         * @class
         * @name CSSManager
         */
        var CSSManager = beez.extend(
            'beez.mvcr.CSSManager',
            function constructor() {
                return this.initialize();
            },
            {

                initialize: function initialize() {
                    this._basePath = ''; // Force / in the end

                    if (beez.config.url && beez.config.url.base) {
                        this._basePath = beez.config.url.base;
                        this._basePath.replace(/\/$/, '');
                    }

                },

                /**
                 * name is changed into path.
                 *
                 * @memberof CSSManager
                 * @insntace
                 * @param {String} name
                 * @return {String}
                 */
                name2path: function name2path(name) {
                    var path = '';
                    if (!this._basePath) {
                        path = name;
                    } else {
                        if (name.indexOf('/') === 0) {
                            path = this._basePath + name;
                        } else {
                            path = this._basePath + '/' + name;
                        }
                    }
                    return path;
                },

                /**
                 * Asynchronous instance generation.
                 *
                 * @memberof CSSManager
                 * @insntace
                 * @return {CSSManagerAsync}
                 */
                async: function async() {
                    return new CSSManagerAsync(this);
                },

                /**
                 * remove the link tag in the path contained in the name.
                 *
                 * @memberof CSSManager
                 * @insntace
                 * @param {String} name
                 */
                remove: function remove(name) {
                    var $stylelinks = $('link[rel=stylesheet]');
                    $stylelinks.each(function () {
                        if (this.href.indexOf(name) !== -1) {
                            logger.debug('remove finished. name:', name, 'path:', this.href);
                            $(this).remove();
                        }
                    });
                    return this;
                },

                /**
                 * Check css path specified in the present.
                 *
                 * @memberof CSSManager
                 * @instance
                 * @param {String} path
                 * @return {boolean}
                 */
                isExists: isExists,

                /**
                 * CSS is loaded?
                 * Warnnig: Relative paths are not expected.
                 *
                 * @memberof CSSManager
                 * @instance
                 * @param {String} path
                 * @return {boolean}
                 */
                isLoaded: isLoaded,

                /**
                 * Disposes of the instance
                 *  @memberof CSSManager
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');
                    delete this._basePath;
                }
            }
        );

        // -------------------
        // return

        return {
            CSSManager: CSSManager,
            CSSManagerAsync: CSSManagerAsync
        };
    });

})(this);

/**
 * @fileOverview CSSManager
 * @name imagemanager.js<beez-mvcr>
 * @author Kei Funagayama <funagayama_kei@cyberagent.co.jp>
 * @overview image management functions
 */

(function (global) {

    define('beez-mvcr/imagemanager',['require','exports','module','beez.core','beez.utils'],function (require, exports, module) {
        

        var beez = require('beez.core');
        var utils = require('beez.utils');
        var _ = beez.vendor._;
        var $ = beez.vendor.$;

        var logger = beez.getLogger('beez.mvcr.imagemanager');

        /**
         * transparent-1px image data
         * @type {String}
         */
        var transparentImageDataURI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAMAAAAoyzS7AAAABlBMVEX///8AAABVwtN+AAAAAXRSTlMAQObYZgAAAA1JREFUeNoBAgD9/wAAAAIAAVMrnDAAAAAASUVORK5CYII=';

        var _uid = 0;
        var uid = function uid() {
            return '__beez_manager_image_uid_' + _uid++;
        };

        /**
         * Class that manages multiple Image Object. re-use function of <img>.
         *
         * @class
         * @name ImangePool
         * @private
         * @param {int} size Pool size. Throw Error when exceeds the specified size. Setting "0", unlimited.
         * @throw {Error}
         */
        var ImangePool = beez.extend(
            'beez.mvcr.ImagePool',
            function constructor(size, options) {
                return this.initialize(size, options);
            },
            {
                /**
                 * Constructor
                 *
                 * @memberof ImangePool
                 * @instance
                 * @param {int} size Pool size. Throw Error when exceeds the specified size. Setting "0", unlimited.
                 * @param {Object} options for creating image
                 */
                initialize: function initialize(size, options) {
                    /**
                     * for creating image
                     *
                     * @memberof ImangePool
                     * @instance
                     * @property {Object} options
                     */
                    this.options = options || {};

                    /**
                     * pool limit
                     *
                     * @memberof ImangePool
                     * @instance
                     * @property {int} limit
                     */
                    this.limit = size;

                    /**
                     * The total number of generated HTMLImageElement
                     *
                     * @memberof ImangePool
                     * @instance
                     * @private
                     */
                    this._total = 0;

                    /**
                     * HTMLImageElement total number in use.
                     *
                     * @memberof ImangePool
                     * @instance
                     * @private
                     */
                    this._num_used = 0;

                    /**
                     * HTMLImageElement hash in use.
                     *
                     * @memberof ImangePool
                     * @instance
                     * @private
                     */
                    this._using = {};

                    /**
                     * Waiting for reuse HTMLImageElement
                     *
                     * @memberof ImangePool
                     * @instance
                     * @private
                     * @return {Array}
                     */
                    this._unused = [];
                },


                /**
                 * Generate HTMLImageElement.
                 *
                 * It is returned when there is recyclable HTMLImageElement.
                 * release() is given to HTMLImageElement.
                 * Please call release () to always While destroying HTMLImageElement.
                 *
                 * @memberof ImangePool
                 * @instance
                 * @param {Object} options for creating image
                 * @return {HTMLImageElement}
                 */
                create: function create(options) {
                    var elem;
                    //options = options || this.options || {}; // default) not "Anonymous"
                    options = options || {}; // default) not "Anonymous"

                    if (this._unused.length > 0) {
                        elem = this._unused.pop();
                    } else {
                        if (this.limit > 0 && this._total >= this.limit) {
                            throw new beez.Error('image pool limit exceeds!');
                        }
                        elem = new Image();
                        elem.__beez_manager_image_uid = uid();
                        this._total++;
                    }

                    //elem.crossOrigin = options.crossOrigin ? options.crossOrigin : elem.crossOrigin;
                    //elem.crossOrigin = options.crossOrigin ? options.crossOrigin : options.crossOrigin;

                    if (options.crossOrigin) {
                        elem.crossOrigin = options.crossOrigin;
                    } else if (this.options.crossOrigin) {
                        elem.crossOrigin = this.options.crossOrigin;
                    }

                    this._num_used++;
                    this._using[elem.__beez_manager_image_uid] = elem;

                    var self = this;

                    /**
                     * The HTMLImageelement waiting for reuse.
                     * This function will be removed in the release() timing.
                     */
                    elem.release = function release() {
                        this.crossOrigin = null; // force null!!
                        this.src = transparentImageDataURI;
                        self._using && delete self._using[this.__beez_manager_image_uid];
                        self._unused && self._unused.push(this);
                        self._num_used && self._num_used--;
                        delete this.release;
                    };

                    return elem;
                },


                /**
                 * It is the number of HTMLImageElement(s) during use.
                 *
                 * @memberof ImangePool
                 * @instance
                 * @returns {int}
                 */
                living: function living() {
                    return this._num_used;
                },


                /**
                 * The total number of HTMLImageElement
                 *
                 * @memberof ImangePool
                 * @instance
                 * @returns {int}
                 */
                peak: function peak() {
                    return this._total;
                },


                /**
                 * Waiting for reuse of HTMLImageElement
                 *
                 * @memberof ImangePool
                 * @instance
                 * @returns {int}
                 */
                waiting: function waiting() {
                    return this._unused.length;
                },

                /**
                 * Disposes of the instance
                 *
                 * @memberof ImangePool
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');
                    // release all of using images
                    for (var id in this._using) {
                        this._using[id].release();
                    }
                    delete this._using;

                    while (this._unused.length > 0) {
                        var e = this._unused.pop();
                        delete e.__beez_manager_image_uid;
                    }
                    delete this._unused;

                    delete this._num_used;
                    delete this._total;
                    delete this._limit;
                }
            }
        );



        /**
         * Image management class. asynchronous
         *
         * @class
         * @name ImageManagerAsync
         * @private
         * @extends Bucks
         * @example
         * var l = new ImageManagerAsync();
         * l.load('http://...').then(res, next) {
         *     // res[0] is loaded image
         * }).end();
         */
        var ImageManagerAsync = beez.Bucks.extend(
            'beez.mvcr.ImageManagerAsync',
            {
                /**
                 * Constructor
                 * @memberof ImageManagerAsync
                 */
                initialize: function initialize(imageManager) {
                    this.imageManager = imageManager;
                },

                /**
                 * Load the image.
                 *
                 * @memberof ImageManagerAsync
                 * @instance
                 * @param {String} url
                 * @param {Object} options for creating image
                 * @return {Bucks}
                 * @example
                 * loader.loadOne('http://...').then(function onload(res, next) {
                 *     // res is a loaded-image
                 *     // next(null, ...)
                 * }).error(function onError(err, next) {
                 *     // on error
                 * }).end();
                 */
                loadOne: function loadOne(url, options) {

                    var img = this.imageManager.create(options);
                    var self = this;

                    return this.add(function loadTask(err, res, next) {

                        var $img = $(img);

                        var onLoad = function onLoad() {
                            $img.off();
                            next(null, img);
                        };
                        var onError = function onError(ev) {
                            var src = img.src;

                            $img.off();
                            img.release();
                            next(new beez.Error('error on load image. src:' + src));
                        };
                        var onAbort = function onAbort(ev) {
                            var src = img.src;

                            $img.off();
                            img.release();
                            next(new beez.Error('image loading aborted. src:' + src));
                        };

                        $img.on('load', onLoad);
                        $img.on('error', onError);
                        $img.on('abort', onAbort);

                        // start loading
                        var _url = self.imageManager.imageUrl(url); // replace ${ratio}
                        img.src = _url;
                    });
                },

                /**
                 * Load the image(s).
                 *
                 * @memberof ImageManagerAsync
                 * @instance
                 * @param {String|Array} url ex) Array: ['hoge.png', 'foo.png']
                 * @param {Object|Array} options ex) Array: [{crossOrigin: "Anonymous"}, {crossOrigin: ""}]
                 * @return {Bucks} ex.) {res:[HTMLImageElement, null, null, HTMLImageElement], err:[null, Error, Error, HTMLImageElement]}
                 */
                load: function load(url, options) {

                    // param check and Array-nize
                    if (_.isString(url)) {
                        url = [url];
                    } else if (!_.isArray(url)) {
                        throw new beez.Error('url can be String or Array of string.');
                    }

                    // param check and Array-nize

                    options = options || {};
                    if (!_.isArray(options)) {
                        if (_.isObject(options)) {
                            options = [options];
                        } else {
                            throw new beez.Error('options can be Object or Array of object.');
                        }
                    }

                    // make tasks
                    var self = this;
                    var tasks = _.map(url, function makeTask(u, idx) {
                        return function loadTask(err, res, next) {
                            new ImageManagerAsync(self.imageManager)
                                .loadOne(u, options[idx])
                                .end(function complete(err, res) {
                                    next(err, res[0]);
                                }, function onError(e) {
                                    next(e);
                                });
                        };
                    });

                    // parallel load
                    return this.parallel(tasks);
                },

                /**
                 * dispose this ImageManagerAsync
                 *
                 * @memberof ImageManagerAsync
                 * @instance
                 * @private
                 */
                dispose: function dispose() {
                    delete this.imageManager;
                }
            }
        );



        /**
         * Image management class. synchronism
         *
         * @class
         * @name ImageManager
         * @param {Object} [options]
         * @param {int} [options.size] Pool size. Throw Error when exceeds the specified size. Setting "0", unlimited.
         */
        var ImageManager = beez.extend(
            'beez.mvcr.ImageManager',
            function constructor(options) {
                return this.initialize(options);
            },
            {
                /**
                 * Constructor
                 *
                 * @memberof ImageManager
                 * @param {Object} options for creating image
                 * @example
                 * var options = {
                 *     size: 10,
                 *     pool: {
                 *         crossOrigin: 'Anonymous'
                 *     }
                 * };
                 *     var manager = new ImageManager(options);
                 *
                 *
                 */
                initialize: function initialize(options) {
                    var size = (options && options.size) ? options.size : 0;
                    var pool = (options && options.pool) ? options.pool : {};
                    this.pool = new ImangePool(size, pool);
                },

                /**
                 * Replaced by pixcelRatio of the URL $ {ratio}
                 *
                 * @memberof ImageManager
                 */
                imageUrl: function imageUrl(url) {
                    return url.replace('${ratio}', beez.utils.pixelRatio * 10);
                },

                /**
                 * Generate HTMLImageElement.
                 *
                 * It is returned when there is recyclable HTMLImageElement.
                 * release() is given to HTMLImageElement.
                 * Please call release () to always While destroying HTMLImageElement.
                 *
                 * @memberof ImageManager
                 * @param {Object} options for creating image
                 * @instance
                 */
                create: function create(options) {
                    return this.pool.create(options);
                },


                /**
                 * It is the number of HTMLImageElement(s) during use.
                 *
                 * @memberof ImageManager
                 * @instance
                 * @returns {int}
                 */
                living: function living() {
                    return this.pool.living();
                },


                /**
                 * The total number of HTMLImageElement
                 *
                 * @memberof ImageManager
                 * @instance
                 * @returns {int}
                 */
                peak: function peak() {
                    return this.pool.peak();
                },


                /**
                 * Waiting for reuse of HTMLImageElement
                 *
                 * @memberof ImageManager
                 * @instance
                 * @returns {int}
                 */
                waiting: function waiting() {
                    return this.pool.waiting();
                },


                /**
                 * Load the image(s).
                 *
                 * @memberof ImageManager
                 * @instance
                 * @param {String|Array} url
                 * @param {Object|Array} options ex) Array: [{crossOrigin: "Anonymous"}, {crossOrigin: ""}]
                 * @return {ImageManagerAsync}
                 * @see ImageManagerAsync#load
                 */
                load: function load(url, options) {
                    return new ImageManagerAsync(this).load(url, options);
                },


                /**
                 * Load the image(s).
                 *
                 * @memberof ImageManager
                 * @instance
                 * @param {String} url
                 * @param {Object} options
                 * @return {ImageManagerAsync}
                 * @see ImageManagerAsync#loadOne
                 */
                loadOne: function loadOne(url, options) {
                    return new ImageManagerAsync(this).loadOne(url, options);
                },

                /**
                 * dispose this ImageManagerAsync
                 *
                 * @memberof ImageManager
                 * @instance
                 * @private
                 */
                dispose: function dispose() {
                    logger.trace(this.constructor.name, 'dispose');
                    this.pool.dispose();
                    delete this.pool;
                }
            }
        );

        return {
            ImageManager: ImageManager,
            ImageManagerAsync: ImageManagerAsync
        };
    });
})(this);

/**
 * @fileOverview beez.mvcr class
 * @name index.js<beez-mvcr>
 * @author Kei Funagayama <funagayama_kei@cyberagent.co.jp>
 */

(function (global) {

    /**
     * mvcr namespace
     * @namespace beez.mvcr
     */
    define('beez.mvcr',['require','exports','module','beez.core','handlebars','beez-mvcr/model','beez-mvcr/modic','beez-mvcr/view','beez-mvcr/controller','beez-mvcr/router','beez-mvcr/cssmanager','beez-mvcr/imagemanager','beez-mvcr/base','backbone','beez-mvcr/model','beez-mvcr/view','beez-mvcr/controller','beez-mvcr/router','beez-mvcr/cssmanager','beez-mvcr/imagemanager'],function __MVCR__(require, exports, module) {
        

        var beez = require('beez.core');
        var logger = beez.getLogger('beez.mvcr');

        if (beez.mvcr) {
            logger.debug('beez.mvcr already defined.');
            return beez.mvcr;
        }

        var Handlebars = require('handlebars');

        /**
         * Shortcut function
         *   Handlebars.templates[]
         * @memberof beez
         * @function
         * @name getTemplate
         * @param {String} name
         * @returns {Function} handlebars template function
         */
        beez.getTemplate = function getTemplate(name) {
            return Handlebars.templates[name];
        };

        var __MVCR__ = {
            initialize: function () {

                var model = require('beez-mvcr/model');
                var modic = require('beez-mvcr/modic');
                var view = require('beez-mvcr/view');
                var controller = require('beez-mvcr/controller');
                var router = require('beez-mvcr/router');
                var css = require('beez-mvcr/cssmanager');
                var image = require('beez-mvcr/imagemanager');
                var base = require('beez-mvcr/base');


                /**
                 * @name Model
                 * @memberof beez.mvcr
                 * @borrows Model
                 * @type {Model}
                 */
                this.Model = model.Model;

                /**
                 * @name ModelManager
                 * @memberof beez.mvcr
                 * @borrows ModelManager
                 * @type {ModelManager}
                 */
                this.ModelManager = model.ModelManager; // if you want to extend

                /**
                 * @name ModelManagerAsync
                 * @memberof beez.mvcr
                 * @borrows ModelManagerAsync
                 * @type {ModelManagerAsync}
                 */
                this.ModelManagerAsync = model.ModelManagerAsync; // if you want to extend

                /**
                 * @name Collection
                 * @memberof beez.mvcr
                 * @borrows Collection
                 * @type {Collection}
                 */
                this.Collection = model.Collection;

                /**
                 * @name Modic
                 * @memberof beez.mvcr
                 * @borrows Modic
                 * @type {Modic}
                 */
                this.Modic = modic.Modic;

                /**
                 * @name View
                 * @memberof beez.mvcr
                 * @borrows View
                 * @type {View}
                 */
                this.View = view.View;

                /**
                 * @name View
                 * @memberof beez.mvcr
                 * @borrows ViewAsync
                 * @type {ViewAsync}
                 */
                this.ViewAsync = view.ViewAsync;

                /**
                 * @name View
                 * @memberof beez.mvcr
                 * @borrows ViewManager
                 * @type {View}
                 */
                this.ViewManager = view.ViewManager; // if you want to extend

                /**
                 * @name View
                 * @memberof beez.mvcr
                 * @borrows ViewManagerAsync
                 * @type {ViewManagerAsync}
                 */
                this.ViewManagerAsync = view.ViewManagerAsync; // if you want to extend


                /**
                 * @name Controller
                 * @memberof beez.mvcr
                 * @borrows Controller
                 * @type {Controller}
                 */
                this.Controller = controller.Controller;

                /**
                 * @name Controller
                 * @memberof beez.mvcr
                 * @borrows ControllerManager
                 * @type {Controller}
                 */
                this.ControllerManager = controller.ControllerManager; // if you want to extend

                /**
                 * @name Controller
                 * @memberof beez.mvcr
                 * @borrows ControllerManagerAsync
                 * @type {ControllerAsync}
                 */
                this.ControllerManagerAsync = controller.ControllerManagerAsync; // if you want to extend

                /**
                 * @name Router
                 * @memberof beez.mvcr
                 * @borrows Router
                 * @type {Router}
                 */
                this.Router = router.Router;

                /**
                 * @name RouterManager
                 * @memberof beez.mvcr
                 * @borrows RouterManager
                 * @type {RouterManager}
                 */
                this.RouterManager = router.RouterManager; // if you want to extend

                /**
                 * @name CSSManager
                 * @memberof beez.mvcr
                 * @borrows CSSManager
                 * @type {CSSManager}
                 */
                this.CSSManager = css.CSSManager;     // if you want to extend
                /**
                 * @name CSSManagerAsync
                 * @memberof beez.mvcr
                 * @borrows CSSManagerAsync
                 * @type {CSSManagerAsync}
                 */
                this.CSSManagerAsync = css.CSSManagerAsync;     // if you want to extend
                /**
                 * @name ImageManager
                 * @memberof beez.mvcr
                 * @borrows ImageManager
                 * @type {ImageManager}
                 */
                this.ImageManager = image.ImageManager; // if you want to extend
                /**
                 * @name ImageManagerAsync
                 * @memberof beez.mvcr
                 * @borrows ImageManagerAsync
                 * @type {ImageManagerAsync}
                 */
                this.ImageManagerAsync = image.ImageManagerAsync; // if you want to extend
                /**
                 * @name ManagerBase
                 * @memberof beez.mvcr
                 * @borrows ManagerBase
                 * @type {ManagerBase}
                 */
                this.ManagerBase = base.ManagerBase;
                /**
                 * @name Base
                 * @memberof beez.mvcr
                 * @borrows Base
                 * @type {Base}
                 */
                this.Base = base.Base;

            }
        };

        var MVCR = beez.extend(
            'beez.MVCR',
            function constructor() {
                return this.initialize();
            }, __MVCR__);

        var mvcr = new MVCR();


        // Add to beez object.
        beez.mvcr = mvcr;

        beez.Model = mvcr.Model;
        beez.Collection = mvcr.Collection;
        beez.Modic = mvcr.Modic;
        beez.View = mvcr.View;
        beez.Controller = mvcr.Controller;
        beez.Router = mvcr.Router;

        // Backbone shortcut
        var Backbone = require('backbone');
        /**
         * Backbone.history short cut.
         * @name history
         * @memberof beez
         */
        beez.history = Backbone.history;

        //
        // ----
        // Managers
        //

        var mconfig = beez.config.manager || {};

        var __Manager__ = {
            initialize: function () {
                /**
                 * setuped flag
                 * @memberof beez.manager
                 * @name setuped
                 * @type {Boolean}
                 */
                this.setuped = false;

                /**
                 * ModelManager instance
                 * @memberof beez.manager
                 * @name model
                 * @alias m
                 * @type {ModelManager}
                 */
                this.model = undefined;

                /**
                 * shortcut for model
                 * @memberof beez.manager
                 * @name m
                 * @type {ModelManager}
                 */
                this.m = undefined;

                /**
                 * ViewManager instance
                 * @memberof beez.manager
                 * @name view
                 * @type {ViewManager}
                 */
                this.view = undefined;

                /**
                 * shortcut for view
                 * @memberof beez.manager
                 * @name v
                 * @type {ViewManager}
                 */
                this.v = undefined;

                /**
                 * ControllerManager instance
                 * @memberof beez.manager
                 * @name controller
                 * @type {ControllerManager}
                 */
                this.controller = undefined;

                /**
                 * shortcut for controller
                 * @memberof beez.manager
                 * @name c
                 * @type {ControllerManager}
                 */
                this.c = undefined;

                /**
                 * RouterManager instance
                 * @memberof beez.manager
                 * @name router
                 * @type {RouterManager}
                 */
                this.router = undefined;

                /**
                 * shortcut for router
                 * @memberof beez.manager
                 * @name r
                 * @type {RouterManager}
                 */
                this.r = undefined;

                /**
                 * CSSManager instance
                 * @memberof beez.manager
                 * @name css
                 * @type {CSSManager}
                 */
                this.css = undefined;

                /**
                 * ImageManager instance
                 * @memberof beez.manager
                 * @name image
                 * @type {ImageManager}
                 */
                this.image = undefined;
            },

            /**
             * Beez MVCR Manager Setup
             *
             * @memberof MVCR
             * @instance
             * @public
             * @param {Object} objs It sets up to overwrite a management class.
             * @return {MVCR}
             */
            setup: function setup(objs) {
                if (this.setuped) {
                    return this;
                }

                objs = objs || {};
                this.setuped = true;

                // Initialize ModelManager
                if (objs.model) {
                    this.model = objs.model;
                } else {
                    var model = require('beez-mvcr/model');
                    this.model = new model.ModelManager('midx');
                }
                this.m = this.model; // shortcut


                // Initialize ViewManager
                if (objs.view) {
                    this.view = objs.view;
                } else {
                    var view = require('beez-mvcr/view');
                    this.view = new view.ViewManager('vidx');
                }
                this.v = this.view; // shortcut

                // Initialize ControllerManager
                if (objs.controller) {
                    this.controller = objs.controller;
                } else {
                    var controller = require('beez-mvcr/controller');
                    this.controller = new controller.ControllerManager();
                }
                this.c = this.controller; // shortcut


                // Initialize RouterManager
                if (objs.router) {
                    this.router = objs.router;
                } else {
                    var router = require('beez-mvcr/router');
                    this.router = new router.RouterManager();
                }
                this.r = this.router; // shortcut

                // Initialize CSSManager
                if (objs.css) {
                    this.css = objs.css;
                } else {
                    var css = require('beez-mvcr/cssmanager');
                    this.css = new css.CSSManager();
                }

                // Initialize ImageManager
                if (objs.image) {
                    this.image = objs.image;
                } else {
                    var image = require('beez-mvcr/imagemanager');
                    this.image = new image.ImageManager(mconfig.image);
                }
                return this;
            }
        };

        var Manager = beez.extend(
            'beez.Manager',
            function constructor() {
                return this.initialize();
            }, __Manager__);

        var manager = new Manager();
        mvcr.manager = manager;
        beez.manager = mvcr.manager; // shortcut

        return beez.mvcr;
    });
})(this);