Execute the save function of a model.js file
for either a component or a layout

@param {Object} model
@param {String} uri
@param {Object} data
@param {Object} locals
@returns {Object}
502209
function put(model, uri, data, locals) {
  const startTime = process.hrtime(),
    timeoutLimit = TIMEOUT_CONSTANT * TIMEOUT_PUT_COEFFICIENT;

  return bluebird.try(() => {
    return bluebird.resolve(model.save(uri, data, locals))
      .then(resolvedData => {
        if (!_.isObject(resolvedData)) {
          throw new Error(`Unable to save ${uri}: Data from model.save must be an object!`);
        }

        return {
          key: uri,
          type: 'put',
          value: JSON.stringify(resolvedData)
        };
      });
  }).tap(() => {
    const ms = timer.getMillisecondsSince(startTime);

    if (ms > timeoutLimit * 0.5) {
      log('warn', `slow put ${uri} ${ms}ms`);
    }
  }).timeout(timeoutLimit, `Module PUT exceeded ${timeoutLimit}ms: ${uri}`);
}
1264931
function store(name, val) {
        if (typeof (Storage) !== 'undefined') {
            localStorage.setItem(name, val)
        } else {
            window.alert('Please use a modern browser to properly view this template!')
        }
    }
895728
function appendModel(url, model, done){
		var list = utils.flatten_tree(JSON.parse(JSON.stringify(model)))

		var errormodel = null

		list = list.filter(function(model){
			if(!model._digger.path || !model._digger.inode){
				errormodel = model;
				return false;
			}
			return true
		})

		if(errormodel){
			return done('no path or inode in level-append: ' + JSON.stringify(model))
		}

		var batch = list.map(function(model){
			return {
				type:'put',
				key:model._digger.path + '/' + model._digger.inode,
				value:model
			}
		})

		tree.batch(batch, function(err){
			if(err) return done(err)
			done(null, model)
		})
	}
1147825
function composePage(pageData, locals) {
  const layoutReference = pageData.layout,
    pageDataNoConf = references.omitPageConfiguration(pageData);

  return components.get(layoutReference)
    .then(layoutData => mapLayoutToPageData(pageDataNoConf, layoutData))
    .then(fullData => resolveComponentReferences(fullData, locals));
}
299583
function mv (sourceURI, destURI, callback) {
  if (!sourceURI) {
    callback(new Error('source URI is required'))
  }
  if (!destURI) {
    callback(new Error('dest URI is required'))
  }
  util.get(sourceURI, function (err, val, uri) {
    util.put(destURI, val, function (err, ret, uri) {
      if (!err) {
        util.rm(sourceURI, function(err, ret) {
          if (!err) {
            callback(null, ret, uri)
          } else {
            callback(err)
          }
        })
      } else {
        callback(err)
      }
    })
  })
}
457373
function loadModels() {
  if(this.config.path.models == false) return;
  var MODEL_LOCATION = Component.appPath(this.config.path.models),
    self = this;
  try {
    var list = Crux.util.readDirectory(MODEL_LOCATION, 'js');
  } catch(e) {
    // Component has no models.
    return;
  }
  list.forEach(function(modelPath) {
    var fileName = Crux.util.getFileName(modelPath);
    var tableName = fileName.replace('.js', '');
    tableName = tableName.replace(/\//g, '_').replace(/\\/g, '_');
    var modelName = Crux.util.capitalize(tableName, true);
    var modelObj = self.Register(modelName, tableName);
    var modelFunc = require(modelPath);
    if(typeof modelFunc !== 'function') {
      log.warn('Crux.sql: failed to load model definition "%s", not a function', modelName);
      return;
    }
    modelFunc(modelObj, Sequelize, self);
    if(!modelObj.hasFields) {
      log.warn('Crux.sql: Model definition "%s" has no fields. Skipping', modelName);
      return;
    }
    var _opt = modelObj.options;
    if(modelObj.hasValidations) {
      _opt['validate'] = {};
      _.forEach(modelObj.validations, function(callback, name) {
        _opt['validate'][name] = callback;
      });
    }
    if(modelObj.hasMethods) {
      _opt['instanceMethods'] = {};
      _.forEach(modelObj.methods, function(callback, name) {
        _opt['instanceMethods'][name] = callback;
      });
    }
    if(modelObj.hasStatics) {
      _opt['classMethods'] = {};
      _.forEach(modelObj.statics, function(callback, name) {
        if(typeof callback === 'function') {
          _opt['classMethods'][name] = callback;
        }
      });
    }
    if(modelObj.hasJsonFields) {
      modelObj.markJsonFields();
    }
    _opt['syncOnAssociation'] = false;
    try {
      MODELS[modelObj.__name] = self.Seq.define(modelObj.__name, modelObj.fields, _opt);
    } catch(e) {
      log.error('crux.sql: Failed to load SQL model definition: %s', modelObj.__name);
      throw e;
    }
    modelObj.bindMethods(MODELS[modelObj.__name]);
    modelObj.bind(MODELS[modelObj.__name]);
    if(modelObj.hasRelationships) {
      RELATIONSHIPS.push(modelObj);
    }
    if(modelObj.hasStatics) {
      _.forEach(modelObj.statics, function(data, fieldName) {
        if(typeof data !== 'function') {
          MODELS[modelObj.__name][fieldName] = data;
        }
      });
    }
  });
  RELATIONSHIPS.forEach(function(modelObj) {
    var sourceModel = MODELS[modelObj.__name];
    /* Has many */
    _.forEach(modelObj.__hasMany, function(depOpt, depName) {
      var targetModel = MODELS[depName];
      if(typeof depOpt['through'] === 'string') {
        depOpt['through'] = MODELS[depOpt['through']];
      }
      try {
        sourceModel.hasMany(targetModel, depOpt);
      } catch(e) {
        log.fatal('Failed to do hasMany on %s-%s',depName, modelObj.__name);
        log.debug(e);
      }
    });
    /* Has one */
    _.forEach(modelObj.__hasOne, function(depOpt, depName) {
      var targetModel = MODELS[depName];
      try {
        sourceModel.hasOne(targetModel, depOpt);
      } catch(e) {
        log.fatal('Failed to do hasOne on %s-%s', depName, modelObj.__name);
        log.debug(e);
      }
    });
    /* Belongs to */
    _.forEach(modelObj.__belongsTo, function(depOpt, depName) {
      var targetModel = MODELS[depName];
      try {
        sourceModel.belongsTo(targetModel, depOpt);
      } catch(e) {
        log.fatal('Failed to do belongsTo on %s-%s', depName, modelObj.__name);
        log.debug(e);
      }
    });
  });
  /*
   * We now bind the mock() function for all our loaded models.
   * */
  _.forEach(MODELS, function(modelObj, name) {
    /*
     * The mock function will be attached on all our models and will return a object model with generated data.
     * */
    modelObj.mock = function MockJsonModel(data) {
      if(typeof data !== 'object' || data === null) data = {};
      var mockData = {};
      // We bind the raw attributes
      for(var attr in modelObj.rawAttributes) {
        if(typeof data[attr] !== 'undefined') {
          mockData[attr] = data[attr];
          continue;
        }
        // If by any change, we have set some default values, we take one of them.
        if(modelObj.rawAttributes[attr].type.values instanceof Array) {
          var idx = Math.floor(Math.random() * modelObj.rawAttributes[attr].type.values.length);
          mockData[attr] = modelObj.rawAttributes[attr].type.values[idx];
          continue;
        }
        // We now generate a random value.
        var rawAttr = modelObj.rawAttributes[attr],
          aName = _.isString(rawAttr.type.type) ? rawAttr.type.type :
            (_.isString(rawAttr.type._typeName) ? rawAttr.type._typeName : rawAttr.type);
        /* If by any chance we have a rawAttribute that is used in foreign keys, we skip it */
        if(typeof rawAttr['references'] !== 'undefined') {
          continue;
        }
        if(aName.indexOf("VARCHAR") !== -1 && (typeof rawAttr.type._parseJson === 'undefined')) {
          mockData[attr] = Crux.util.uniqueId(5);
        }
        if(aName.indexOf("INTEGER") !== -1) {
          mockData[attr] = Math.floor(Math.random() * 100);
        }
        if(aName.indexOf("FLOAT") !== -1) {
          mockData[attr] = parseFloat(Math.random().toFixed(3));
        }
        if(aName.indexOf("DATE") !== -1) {
          mockData[attr] = new Date();
        }
        if(aName.indexOf("BOOLEAN") !== -1) {
          var now = new Date().getTime();
          mockData[attr] = (now % 2 === 0 ? true : false);
        }
      }
      var buildedMockObj = modelObj.build(mockData);
      // We now go through the model's associations.
      // We only create the association if the user explicitly states it
      for(var assocName in modelObj.associations) {
        var assocObj = modelObj.associations[assocName];
        if(typeof data[assocName] === 'undefined') continue;
        if(assocObj.associationType === 'HasMany' && data[assocName] instanceof Array) {
          //buildedMockObj.setDataValue(assocObj.associationAccessor, []);
          var _mocks = [];
          for(var i=0; i < data[assocName].length; i++) {
            var targetMock = assocObj.target.mock(data[assocName][i]);
            _mocks.push(targetMock);
          }
          if(_mocks.length !== 0) {
            buildedMockObj.setDataValue(assocName, _mocks);
          }
          continue;
        }
        if((assocObj.associationType === 'BelongsTo' || assocObj.associationType === 'HasOne') && typeof data[assocName] === 'object') {
          var targetMock = assocObj.target.mock(data[assocName]).toJSON();
          buildedMockObj.setDataValue(assocName, targetMock);
          continue;
        }
      }
      return buildedMockObj;
    };
  });
}
1357840
function compileFile(locals, cb) {
    getSourceTemplate(function(err, source, template) {
      if (err) return cb(err);

      // Try to get the layout
      parseLayout(source, filename, function(err, layoutTemplates) {
        if (err) return cb(err);

        function renderIt(layoutTemplates) {
          if (self._options.beautify) {
            return render(template, locals, layoutTemplates, function(err, html) {
              if (err) return cb(err);
              loadBeautify();
              return cb(null, self.beautify(html, self.beautifyrc));
            });
          }
          return render(template, locals, layoutTemplates, cb);
        }

        // Determine which layout to use

        if (typeof options.layout !== 'undefined' && !options.layout) {
          // If options.layout is falsy, behave as if no layout should be used - suppress defaults
          renderIt(null);
        } else if (layoutTemplates) {
          // 1. Layout specified in template
          renderIt(layoutTemplates);
        } else if (typeof options.layout !== 'undefined' && options.layout) {
          // 2. Layout specified by options from render
          var layoutFile = self.layoutPath(filename, options.layout);
          self.cacheLayout(layoutFile, options.cache, function(err, layoutTemplates) {
            if (err) return cb(err);
            renderIt(layoutTemplates);
          });
        } else if (self.defaultLayoutTemplates) {
          // 3. Default layout specified when middleware was configured.
          renderIt(self.defaultLayoutTemplates);
        } else {
          // render without a template
          renderIt(null);
        }
      });
    });
  }
111274
function saveResolvedLocalsInData() {
    var localNames = previousOrParentNode.tNode.localNames;
    if (localNames) {
        for (var i = 0; i < localNames.length; i += 2) {
            var index = localNames[i + 1];
            var value = index === -1 ? previousOrParentNode.native : directives[index];
            viewData.push(value);
        }
    }
}
258437
function(data) {
    if(!data || !data.sys) {
      return;
    }
    dict = data.sys.dict;
    var protos = data.sys.protos;

    //Init compress dict
    if(dict) {
      dict = dict;
      abbrs = {};

      for(var route in dict) {
        abbrs[dict[route]] = route;
      }
    }

    //Init protobuf protos
    if(protos) {
      protoVersion = protos.version || 0;
      serverProtos = protos.server || {};
      clientProtos = protos.client || {};

        //Save protobuf protos to localStorage
        window.localStorage.setItem('protos', JSON.stringify(protos));

        if(!!protobuf) {
          protobuf.init({encoderProtos: protos.client, decoderProtos: protos.server});
        }
        if(!!decodeIO_protobuf) {
          decodeIO_encoder = decodeIO_protobuf.loadJson(clientProtos);
          decodeIO_decoder = decodeIO_protobuf.loadJson(serverProtos);
        }
      }
    }
1176170
function(model, options) {
      options = options ? _.clone(options) : {};
      var wait = options.wait;
      model = this._prepareModel(model, options);
      if (!model) return false;
      if (!wait) this.add(model, options);
      var collection = this;
      var success = options.success;
      options.success = function(m, resp, callbackOpts) {
        if (wait) collection.add(m, callbackOpts);
        if (success) success.call(callbackOpts.context, m, resp, callbackOpts);
      };
      model.save(null, options);
      return model;
    }
521849
function(model, options) {
    options = options ? extend({}, options) : {};
    if (!(model = this._prepareModel(model, options))){
      return false;
    }
    if (!options.wait){
      this.add(model, options);
    }
    var collection = this;
    options.cb = options.callback;
    options.callback = function cb(err, model, response){
      if (err){
        return callback(err, model, response, options);
      }
      if (options.wait){
        collection.add(model, options);
      }
      callback(null, model, response, options);
    };

    model.save(null, options);
    return model;
  }
1179320
function update(model) {
  var params = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];

  if (!model) {
    throw new Error('No model provided.');
  }
  var currentState = model.toJSON({ shallow: true });
  currentState.id = String(currentState.id);

  return _destructure2['default'](model, params).then(function (destructured) {
    var attributes = destructured.attributes;
    var relations = destructured.relations;

    return _transact2['default'](model, function (transaction) {
      return model.save(attributes, {
        patch: true,
        method: 'update',
        transacting: transaction
      }).tap(function (model) {
        return _relate2['default'](model, relations, 'update', transaction);
      }).then(function (model) {
        // if model didn't change, return null
        // model.previousAttributes() is broken.
        // https://github.com/tgriesser/bookshelf/issues/326
        var updatedState = model.toJSON({ shallow: true });
        updatedState.id = String(updatedState.id);
        return _lodash2['default'].isEqual(currentState, updatedState) ? null : model;
      });
    });
  });
}
1197038
function modelItem(data, model) {
    var res = {};

    utils.defineProperties(res, {
        _isModelItem: { value: true },

        model: { value: model.value },

        update: { value: function(data, sync) {
            if (sync == null) sync = true;

            return update(res, model, data).then(function() {
                if (!sync) return;
                return res.save();
            });
        } },

        save: { value: function() {
            if (_.has(res, 'id')) {
                var props = serverProperties(res, model);
                return utils.socketPost(model.io, model.url + '/update/' + res.id, props.properties).then(function() {
                    return Promise.all(_.map(props.refresh, function(item) {
                        return item.refresh();
                    }));
                });
            }
            return create(res, model);
        } },

        refresh: { value: function() {
            if (!_.has(res, 'id')) return create(res, model);

            return utils.socketGet(model.io, model.url + '/' + res.id).then(function(data) {
                return update(res, model, data, { noRefresh: true });
            });
        } },

        delete: { value: function() {
            model._removeItem(res);
            return utils.socketDelete(model.io, model.url, { id: res.id });
        } },

        matches: { value: function(query) {
            return utils.socketGet(model.io, model.url, query).then(function(r) {
                for (var i = 0; i < r.length; i++) {
                    if (r[i].id === res.id) return true;
                }
                return false;
            });
        } },

        then: { value: function() {
            return res.ready.then.apply(res.ready, arguments);
        } },

        catch: { value: function() {
            return res.ready.catch.apply(res.ready, arguments);
        } }
    });

    res.ready = Promise.resolve();

    update(res, model, data || {});

    return res;
}
413146
function transformModel (options, data) {
  const prop = (options.model && options.model.prop) || 'value'
  const event = (options.model && options.model.event) || 'input';
  (data.props || (data.props = {}))[prop] = data.model.value
  const on = data.on || (data.on = {})
  if (isDef(on[event])) {
    on[event] = [data.model.callback].concat(on[event])
  } else {
    on[event] = data.model.callback
  }
}
126472
function saveFixture( name, data, directory ) {
    return fs.readFileAsync( template, 'utf8' )
      .then( function renderTemplate( template ) {
        return mustache.render( template, { stylesheets: stylesheets, sections: data } );
      }).then( function saveTemplate( templateData ) {
        return fs.outputFileAsync( destination + '/' + name + '.html', templateData );
      });
  }
1357095
function ViewModel(options) {
    // inherit Compiler

    var vm = this
    var el = options.el
    var components = [gcomps, options.components || {}]
    var directives = allDirectives.concat([options.directives || {}])

    var _directives = [] // local refs for all directives instance of the vm    
    var _components = [] // local refs for all components    
    var NS = conf.namespace
    var componentProps = [NS + 'component', NS + 'data', NS + 'methods', NS + 'ref', NS + 'replace']
    var $childrens = options.$childrens

    // set $parent ref
    vm.$parent = options.$parent || null

    /**
     *  Mounted element detect
     */
    if (util.type(el) == 'string') {
        el = document.querySelector(el)
    } 
    if (el && options.template) {
        el.innerHTML = options.template
    } else if (options.template) {
        el = document.createElement('div')
        el.innerHTML = options.template
    } else if (!is.Element(el)) {
        throw new Error('Unmatch el option')
    }

    // replace "$NS-template" of actual instance's DOM  
    if (el.children.length == 1 && el.firstElementChild.tagName.toLowerCase() == (NS + 'template')) {
        var $holder = el.firstElementChild
        var childNodes = _slice($holder.childNodes)
        var attributes = _slice($holder.attributes)

        el.removeChild($holder)
        /**
         *  Migrate childNodes
         */
        $(childNodes).appendTo(el)
        /**
         *  Merge attributes
         */
        attributes.forEach(function (att) {
            var nv
            if (att.name == 'class') {
                nv = att.value + (el.className 
                                    ? ' ' + el.className 
                                    : '')

            } else if (!el.hasAttribute(att.name)) {
                nv = att.value
            } else {
                return
            }
            el.setAttribute(att.name, nv)
        })
    }
    // content insertion
    var points = _slice(el.querySelectorAll('content'))
    if (points) {
        var $con
        if ($childrens && $childrens.length) {
            $con = document.createDocumentFragment()
            _slice($childrens).forEach(function (n) {
                $con.appendChild(n)
            })
        }
        points.forEach(function (p) {
            if (!$childrens || !$childrens.length) {
                return $(p).remove()
            }
            var $p = $(p)
            var select = $p.attr('select')
            var tar
            var ind

            if (select 
                && (tar = $con.querySelector(select)) 
                && ~(ind = $childrens.indexOf(tar)) ) {

                $p.replace(tar)
                $childrens.splice(ind, 1)
            } else if (!select) {
                $p.replace($con)
                $childrens = null
            }
        })
    }

    /**
     * Replace external component element holder with internal child element
     */
    if (options.replace) {
        if (el.children.length !== 1) {
            console.warn('Can\'t using \'' + NS + 'replace=true\' for a component that has no or multiple child-elements.')
        } else if (el.parentNode) {
            var replacedEl = el.firstElementChild
            _cloneArributes(replacedEl, el)
            el.parentNode.replaceChild(replacedEl, el)
            el = replacedEl
        } else {
            el = el.firstElementChild
        }
    }

    vm.$el = el

    /**
     *  get component define by tagName
     */
    vm.$component = getComponent

    /**
     *  Component instance refs
     */
    vm.$refs = {}

    /**
     *  assign methods
     */
    var methods = {}
    util.objEach(options.methods, function(k, v) {
        if (util.type(v) !== 'function') return console.warn(k + ' is not a function.')
        vm[k] = methods[k] = util.bind(v, vm)
    })
    vm.$methods = methods

    var $data
    var dataOpt = {}

    Object.defineProperty(vm, '$data', {
        enumerable: true,
        get: function() {
            // $data will be undefined in created calling, so using dataOpt as temporary
            return $data || dataOpt
        },
        set: function(v) {
            if (!$data) return util.merge(dataOpt, v)

            $data.$set(v)
            return $data
        }
    })
    vm.$set = function () {
        $data.$set.apply($data, arguments)
    }
    vm.$get = function () {
        return $data.$get.apply($data, arguments)
    }
    vm.$watch = function (/*[ keypath ], fn*/) {
        return $data.$watch.apply($data, arguments)
    }
    vm.$unwatch = function (/*[ keypath ], fn*/) {
        return $data.$unwatch.apply($data, arguments)
    }

    var created = options.created
    if (options.$data) {
        $data = options.$data
        // if state model instance passsing, call after set
        created && created.call(vm)
    } else {
        util.merge(dataOpt, _funcOrObject(options, 'data'))
        // Call before vm-$data instance
        created && created.call(vm)
        // Instance observable state model
        var mopts = {
            props: dataOpt,
            computed: options.computed,
            computedContext: vm
        }
        $data = new Mux(mopts)
    }

    /**
     *  DOM Compile
     *  @TODO the unique interface for a compiled node($el, $remove)
     */
    vm.$compile = function (el, scope) {
        var compiler

        util.walk(el, function (node) {
            var isRoot = node === el
            var result = compile(node, scope, isRoot)
            if (isRoot) compiler = result.inst
            return result.into
        })
        return compiler
    }

    var beforeDestroy = options.destroy
    vm.$destroy = function () {
        if (vm.$destroyed) return
        beforeDestroy && beforeDestroy.call(vm)

        ;[_components, _directives].forEach(function (items) {
            items.forEach(function (inst) {
                inst.$destroy()
            })
        })

        $data.$destroy()

        // instance methods/properties
        vm.$el = null
        vm.$get = null
        vm.$set = null
        vm.$refs = null
        vm.$watch = null
        vm.$unwatch = null
        vm.$compile = null
        vm.$component = null

        // private vars
        directives = null
        components = null
        _directives = null
        _components = null

        // marked
        vm.$destroyed = true
    }
    vm.$compiler = vm.$compile(el)

    /**
     *  Call ready after compile
     */
    options.ready && options.ready.call(vm)

    function _getAllDirts () {
        var _dirts = {}
        directives.forEach(function(group) {
            util.objEach(group, function(id, def) {
                _dirts[NS + id] = def
            })
        })
        return _dirts
    }
    function _setBindings2Scope (scope, ref) {
        scope && scope.bindings && (scope.bindings.push(ref))
    }
    function compile (node, scope, isRoot) {
        /**
         *  1. ELEMENT_NODE; 
         *  2. ATTRIBUTE_NODE; 
         *  3. TEXT_NODE; 
         *  8. COMMENT_NODE; 
         *  9. DOCUMENT_NODE; 
         *  11. DOCUMENT_FRAGMENT;
         */
        var into = true
        var inst
        switch (node.nodeType) {
            case 1:
                /**
                 * static block no parsing
                 */
                if (node.hasAttribute(NS + 'static')) {
                    into = false
                    break
                }
                /**
                 * convert those $ns-if, $ns-repeat attribute to block element
                 */
                node = compilePseudoDirectiveElement(node)
                /**
                 *  scope syntax
                 */
                if (inst = compileElement(node, scope, isRoot)) {
                    into = false
                    break
                }
                /**
                 *  Attribute directive
                 */
                compileDirective(node, scope)
                /**
                 *  Compile custom-element
                 */
                if (inst = compileComponent(node, vm, scope, isRoot)) {
                    into = false
                    break
                }
                break
            case 3:
                // ignore whitespace
                if (node.nodeValue.trim()) inst = compileText(node, vm, scope, isRoot)
                into = false
                break
            case 11:
                // document fragment
                break
            default:
                into = false
        }
        return {
            into: !!into,
            inst: !inst && isRoot ? new Compiler(node) : inst
        }
    }

    function compilePseudoDirectiveElement (node) {
        var repeatAttName = NS + 'repeat'
        var ifAttName = NS + 'if'
        var valueAttName
        var matchedAttName

        if (node.hasAttribute(ifAttName)) {
            matchedAttName = ifAttName
            valueAttName = 'is'
        } else if (node.hasAttribute(repeatAttName)) {
            matchedAttName = repeatAttName
            valueAttName = 'items'
        } else {
            return node
        }
        var attValue = node.getAttribute(matchedAttName)
        var blockNode = document.createElement(matchedAttName)
        node.removeAttribute(matchedAttName)
        node.parentNode && node.parentNode.replaceChild(blockNode, node)
        blockNode.appendChild(node)
        blockNode.setAttribute(valueAttName, attValue)

        while(node.hasAttribute(ifAttName) || node.hasAttribute(repeatAttName)) {
            compilePseudoDirectiveElement(node)
        }
        return blockNode
    }

    /**
     *  Reverse component Constructor by tagName
     */
    function getComponent(tn) {
        var cid = tn.toLowerCase()
        var compDef
        components.some(function (comp) {
            if (comp.hasOwnProperty(cid)) {
                compDef = comp[cid]
                return true
            }
        })
        return compDef
    }
    /**
     *  Compile element for block syntax handling
     */
    function compileElement(node, scope, isRoot) {
        var tagName = node.tagName
        var inst
        switch(true) {
            /**
             *  <*-if></*-if>
             */
            case is.IfElement(tagName):
                var children = _slice(node.children)
                var exprs = [$(node).attr('is')]
                children.forEach(function(c) {
                    if (is.ElseElement(c)) {
                        exprs.push($(c).attr(conf.namespace + 'else') || '')
                    }
                })
                inst = new ElementDirective(
                        vm, 
                        scope,
                        node, 
                        elements['if'], 
                        NS + 'if', 
                        exprs
                )
                if (!isRoot) {
                    inst.$mount(node)
                }
                // save elements refs
                _directives.push(inst)
                // save bindins to scope
                _setBindings2Scope(scope, inst)
                return inst
            /**
             *  <*-repeat></*-repeat>
             */
            case is.RepeatElement(tagName):
                inst = new ElementDirective(
                        vm, 
                        scope,
                        node, 
                        elements.repeat,
                        NS + 'repeat', 
                        $(node).attr('items')
                )
                if (!isRoot) {
                    inst.$mount(node)
                }
                _directives.push(inst)
                _setBindings2Scope(scope, inst)
                return inst
        }
    }

    /**
     *  comment
     */
    function compileComponent (node, parentVM, scope) {
        var cAttName = NS + 'component'
        var CompName = node.getAttribute(cAttName)
        var tagName = node.tagName
        // filtrate most no-compoment element
        if (!CompName && (tagName == 'DIV' || tagName == 'SPAN' || tagName == 'A' || tagName == 'IMG')) return
        CompName = CompName || tagName
        var Comp = getComponent(CompName)

        /**
         *  Tag is not a custom component element
         */
        if (!Comp) return
        var $node = $(node)
        $node.removeAttr(cAttName)

        // don't need deep into self
        if (node === parentVM.$el) return
        // suport expression, TBD
        var refName = NS + 'ref'
        var dAttName = NS + 'data'
        var mAttName = NS + 'methods'
        var rAttName = NS + 'replace'

        var ref = $node.attr(refName)
        var dataExpr = $node.attr(dAttName)
        var methods = $node.attr(mAttName)
        var replace = $node.attr(rAttName)

        $node.removeAttr(refName)
             .removeAttr(dAttName)
             .removeAttr(mAttName)
             .removeAttr(rAttName)

        var _isDataExpr = _isExpr(dataExpr)
        var bindingData
        var bindingMethods
        /**
         *  Watch
         */
        var execLiteral = Expression.execLiteral
        var ast = {}
        var revealAst = {}
        var compVM

        function _parseExpr (exp) {
            var name
            exp = exp.replace(/^[^:]+:/, function (m) {
                            name = m.replace(/:$/, '').trim()
                            return ''
                        }).trim()
            return {
                name: name,
                expr: exp,
                vars: Expression.extract(exp)
            }
        }
        function _setBindingObj (expr) {
            var r = _parseExpr(expr)
            ast[r.name] = r
            ;(r.vars || []).forEach(function (v) {
                !revealAst[v] && (revealAst[v] = []);
                !~revealAst[v].indexOf(r.name) && revealAst[v].push(r.name)
            })
        }

        bindingData = execLiteral(dataExpr, parentVM, scope)
        bindingMethods = execLiteral(methods, parentVM, scope) // --> bindingMethods
        
        compVM = new Comp({
            el: node,
            data: bindingData,
            methods: bindingMethods,
            $parent: parentVM,
            $childrens: _slice(node.childNodes),
            replace: replace == 'true'
        })

        var plainDataExpr = _isDataExpr ? Expression.strip(dataExpr) : ''
        var sep = Expression.sep

        if (plainDataExpr) {
            if (plainDataExpr.match(sep)) {
                plainDataExpr.replace(new RegExp(sep + '\\s*$'), '') // trim last seperator
                       .split(sep)
                       .forEach(_setBindingObj)
            } else {
                _setBindingObj(plainDataExpr)
            }
        }
        // watch and binding
        if (_isDataExpr) {
            parentVM.$data.$watch(function (keyPath) {
                var nextState
                util.objEach(revealAst, function (varName, bindingNames) {
                    if (keyPath.indexOf(varName) === 0) {
                        ;!nextState && (nextState = {})
                        bindingNames.forEach(function (n) {
                            nextState[n] = execute(parentVM, scope, ast[n].expr)
                        })
                    }
                })
                nextState && compVM.$set(nextState)
            })
        }
        // set ref to parentVM
        ref && (parentVM.$refs[ref] = compVM)

        _components.push(compVM)
        _setBindings2Scope(scope, compVM)
        // TBM -- to be modify, instance method should not be attached here
        compVM.$update = function () {
            _isDataExpr && compVM.$set(execLiteral(dataExpr, parentVM, scope))
        }
        return compVM
    }
    /**
     *  Compile attributes to directive
     */
    function compileDirective (node, scope) {
        var ast = {
                attrs: {},
                dires: {}
            }
        var dirtDefs = _getAllDirts()
        /**
         *  attributes walk
         */
        _slice(node.attributes).forEach(function(att) {
            var aname = att.name
            var v = att.value
            // parse att
            if (~componentProps.indexOf(aname)) {
                return
            } else if (_isExpr(aname)) {
                // variable attribute name
                ast.attrs[aname] = v
            } else if (aname.indexOf(NS) === 0) {
                var def = dirtDefs[aname]
                if (def) {
                    // directive
                    ast.dires[aname] = {
                        def: def,
                        expr: v
                    }
                } else {
                    return
                }
            } else if (_isExpr(v.trim())) {
                // named attribute with expression
                ast.attrs[aname] = v
            } else {
                return
            }
            node.removeAttribute(aname)
        })

        /**
         *  Attributes binding
         */
        util.objEach(ast.attrs, function(name, value) {
            var attd = new AttributeDirective(vm, scope, node, name, value)
            _directives.push(attd)
            _setBindings2Scope(scope, attd)
        })

        /**
         *  Directives binding
         */
        util.objEach(ast.dires, function(dname, spec) {
            var def = spec.def
            var expr = spec.expr
            var sep = ';'
            var d
            // multiple defines expression parse
            if (def.multi && expr.match(sep)) {
                Expression.strip(expr)
                        .split(sep)
                        .forEach(function(item) {
                            // discard empty expression 
                            if (!item.trim()) return
                            
                            d = new Directive(vm, scope, node, def, dname, '{' + item + '}')
                            _directives.push(d)
                            _setBindings2Scope(scope, d)
                        })
            } else {
                d = new Directive(vm, scope, node, def, dname, expr)
                _directives.push(d)
                _setBindings2Scope(scope, d)
            }
        })
    }

    function compileText (node, vm, scope) {
        var originExpr = node.nodeValue
        var v = Expression.veil(originExpr)
        var exprReg = Expression.exprRegexp

        var parts = v.split(exprReg)
        var exprs = v.match(exprReg)

        var inst
        // expression match or not
        if (exprs && exprs.length) {
            inst = new TextDirective(vm, scope, node, originExpr, parts, exprs)
            _directives.push(inst)
            _setBindings2Scope(scope, inst)
        }
        return inst
    }
}
851468
function saveData(data) {
    console.log('saving data', data);
    if (options.cacheKeys) {
      cachedKeys = Object.keys(data);
    }
    if (file === false) {
      return Promise.resolve();
    } else {
      return writeFile(file, JSON.stringify(data, null, 2));
    }
  }