<commit_before>var MongoClient = require('mongodb').MongoClient;

/**
 * search all talks
 * @param index     full-text index path string
 * @param q         string query to search
 * @param callback  function to execute with the resulting data
 */
exports.search = function(index, q, callback) {
    "use strict";
    var si = require('search-index')({
        indexPath: index
    });
    si.search(q, function(err, results) {
        if (err) {
            throw new Error(err);
        }
        return callback(null, results);
    });
};

/**
 * get all the talks
 * @param dburl     database url string
 * @param callback  function to execute with the resulting data
 */
exports.all = function(dburl, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks
            .find({})
            .toArray(function(err, docs) {
                if (err) {
                    return callback(err, null);
                }
                db.close();
                return callback(null, docs);
            });
    });
};

/**
 * get the latest talks
 * @param dburl         database url string
 * @param quantity      number of results to get
 * @param pageNumber    page number to get results
 * @param callback      function to execute with the resulting data
 */
exports.latest = function(dburl, quantity, pageNumber, callback) {
    "use strict";
    var sort = {
        created: -1
    };
    return searchTalks(dburl, {}, sort, quantity, pageNumber, callback);
};

/**
 * get the most popular talks
 * @param dburl         database url string
 * @param quantity      number of results to get
 * @param pageNumber    page number to get results
 * @param callback      function to execute with the resulting data
 */
exports.popular = function(dburl, quantity, pageNumber, callback) {
    "use strict";
    var conds = {};
    var sort = {
        voteCount: -1,
        viewCount: -1
    };
    return searchTalks(dburl, conds, sort, quantity, pageNumber, callback);
};

/**
 * generic method for getting talks
 * @param dburl         database url string
 * @param conds         search and filter conditions
 * @param sort          sorting conditions
 * @param quantity      number of results to fetch
 * @param pageNumber    page number to get
 * @param callback      function to execute with the resulting data
 */
function searchTalks(dburl, conds, sort, quantity, pageNumber, callback) {
    "use strict";
    var pageNumber = pageNumber || 1;
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks
            .find(conds)
            .sort(sort)
            .skip(pageNumber > 0 ? ((pageNumber - 1) * quantity) : 0)
            .limit(quantity)
            .toArray(function(err, docs) {
                if (err) {
                    return callback(err, null);
                }
                db.close();
                return callback(null, docs);
            });
    });
}

/**
 * create a new talk
 * @param dburl     database url string
 * @param obj       number of results to get
 * @param callback  function to execute with the resulting data
 */
exports.createTalk = function(dburl, obj, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.insert(obj, function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};

/**
 * delete a talk by its id
 * @param dburl     database url string
 * @param id        talk id string
 * @param callback  function to execute with the resulting data
 */
exports.deleteTalk = function(dburl, id, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.remove({
            id: id
        }, function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};

/**
 * get a talk by its id
 * @param dburl     database url string
 * @param id        talk id string
 * @param callback  function to execute with the resulting data
 */
exports.get = function(dburl, id, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.findOne({
            id: id
        }, function(err, doc) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, doc);
        });
    });
};

/**
 * upvote a talk
 * @param dburl     database url string
 * @param id        Talk id
 * @param userid    User that upvotes the talk
 * @param callback  function to execute with the resulting data
 */
exports.upvote = function(dburl, id, userid, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.update({
            "id": id,
            "votes": {
                "$ne": userid
            }
        }, {
            "$inc": {
                "voteCount": 1
            },
            "$push": {
                "votes": userid
            }
        }, function(err, talk) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, talk);
        });
    });
};

/**
 * favorite a talk
 * @param dburl     database url string
 * @param id        Talk id
 * @param userid    User that favorites the talk
 * @param callback  function to execute with the resulting data
 */
exports.favorite = function(dburl, id, userid, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.update({
            "id": id,
            "favorites": {
                "$ne": userid
            }
        }, {
            "$inc": {
                "favoriteCount": 1
            },
            "$push": {
                "favorites": userid
            }
        }, function(err, talk) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, talk);
        });
    });
};

/**
 * unfavorite a talk
 * @param dburl     database url string
 * @param id        Talk id
 * @param userid    User that favorites the talk
 * @param callback  function to execute with the resulting data
 */
exports.unfavorite = function(dburl, id, userid, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.update({
            "id": id,
            "favorites": {
                "$in": [userid]
            }
        }, {
            "$inc": {
                "favoriteCount": -1
            },
            "$pull": {
                "favorites": userid
            }
        }, function(err, talk) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, talk);
        });
    });
};

/**
 * rank a a talk
 * Update raking score field
 * @param dburl     database url string
 * @param id        Talk Unique ID
 * @param score     Raking score
 * @param callback  function to execute with the resulting data
 */
exports.rank = function(dburl, id, score, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.update({
            "id": id
        }, {
            $set: {
                "ranking": score
            }
        }, function(err) {
            if (err) {
                return callback(err);
            }
            db.close();
            return callback(null);
        });
    });
};

/**
 * play a talk
 * Updates views field by 1.
 * @param dburl     database url string
 * @param slug      Talk slug
 * @param callback  function to execute with the resulting data
 */
exports.play = function(dburl, slug, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.findOne({
            "slug": slug
        }, function(err, talk) {
            if (err) {
                return callback(err, null);
            }
            talk.viewCount = talk.viewCount + 1;
            talks.update({
                "slug": slug
            }, {
                $inc: {
                    "viewCount": 1
                },
                $set: {
                    updated: Date.now()
                }
            }, function(err) {
                if (err) {
                    return callback(err, null);
                }
                db.close();
                return callback(null, talk);
            });
        });
    });
};

/**
 * get a talk by tag
 * @param dburl         database url string
 * @param tag           talk tag string
 * @param pageNumber    page number to get
 * @param callback      function to execute with the resulting data
 */
exports.getByTag = function(dburl, tag, pageNumber, callback) {
    "use strict";
    var conds = {
        tags: tag
    };
    var sort = {
        voteCount: -1,
        viewCount: -1
    };
    var pageNumber = pageNumber || 1;
    var quantity = 10;
    return searchTalks(dburl, conds, sort, quantity, pageNumber, callback);
};

/**
 * get a talk by its slug field
 * @param dburl         database url string
 * @param slug          talk slug string
 * @param callback      function to execute with the resulting data
 */
exports.getBySlug = function(dburl, slug, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.find({
            "slug": slug
        }).toArray(function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};

/**
 * get reltated talks from a list of tags
 * @param dburl     string      database url string
 * @param id        int         referenced talk
 * @param tags      Array       list of tag strings
 * @param callback  function    to execute with the resulting data
 */
exports.related = function(dburl, id, tags, quantity, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks
            .find({
                "tags": {
                    $in: tags
                },
                "id": {
                    "$ne": id
                }
            })
            .limit(quantity)
            .toArray(function(err, docs) {
                if (err) {
                    return callback(err, null);
                }
                db.close();
                return callback(null, docs);
            });
    });
};

/**
 * get a talk by its id
 * @param dburl     database url string
 * @param id        author id string
 * @param callback  function to execute with the resulting data
 */
exports.getByAuthorId = function(dburl, id, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.find({
            "author.id": id
        }).sort({
            "created": -1
        }).toArray(function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};

/**
 * get list of talks upvoted by an user
 * @param dburl     database url string
 * @param userid    author id string
 * @param callback  function to execute with the resulting data
 */
exports.getUpvotedByAuthorId = function(dburl, userid, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.find({
            "votes": {
                "$in": [userid]
            }
        }).sort({
            "created": -1
        }).toArray(function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};

/**
 * get list of talks favorited by an user
 * @param dburl     database url string
 * @param userid    author id string
 * @param callback  function to execute with the resulting data
 */
exports.getFavoritedByAuthorId = function(dburl, userid, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.find({
            "favorites": {
                "$in": [userid]
            }
        }).sort({
            "created": -1
        }).toArray(function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};
<commit_msg>Remove default pageNumber on getByTag<commit_after>var MongoClient = require('mongodb').MongoClient;

/**
 * search all talks
 * @param index     full-text index path string
 * @param q         string query to search
 * @param callback  function to execute with the resulting data
 */
exports.search = function(index, q, callback) {
    "use strict";
    var si = require('search-index')({
        indexPath: index
    });
    si.search(q, function(err, results) {
        if (err) {
            throw new Error(err);
        }
        return callback(null, results);
    });
};

/**
 * get all the talks
 * @param dburl     database url string
 * @param callback  function to execute with the resulting data
 */
exports.all = function(dburl, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks
            .find({})
            .toArray(function(err, docs) {
                if (err) {
                    return callback(err, null);
                }
                db.close();
                return callback(null, docs);
            });
    });
};

/**
 * get the latest talks
 * @param dburl         database url string
 * @param quantity      number of results to get
 * @param pageNumber    page number to get results
 * @param callback      function to execute with the resulting data
 */
exports.latest = function(dburl, quantity, pageNumber, callback) {
    "use strict";
    var sort = {
        created: -1
    };
    return searchTalks(dburl, {}, sort, quantity, pageNumber, callback);
};

/**
 * get the most popular talks
 * @param dburl         database url string
 * @param quantity      number of results to get
 * @param pageNumber    page number to get results
 * @param callback      function to execute with the resulting data
 */
exports.popular = function(dburl, quantity, pageNumber, callback) {
    "use strict";
    var conds = {};
    var sort = {
        voteCount: -1,
        viewCount: -1
    };
    return searchTalks(dburl, conds, sort, quantity, pageNumber, callback);
};

/**
 * generic method for getting talks
 * @param dburl         database url string
 * @param conds         search and filter conditions
 * @param sort          sorting conditions
 * @param quantity      number of results to fetch
 * @param pageNumber    page number to get
 * @param callback      function to execute with the resulting data
 */
function searchTalks(dburl, conds, sort, quantity, pageNumber, callback) {
    "use strict";
    var pageNumber = pageNumber || 1;
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks
            .find(conds)
            .sort(sort)
            .skip(pageNumber > 0 ? ((pageNumber - 1) * quantity) : 0)
            .limit(quantity)
            .toArray(function(err, docs) {
                if (err) {
                    return callback(err, null);
                }
                db.close();
                return callback(null, docs);
            });
    });
}

/**
 * create a new talk
 * @param dburl     database url string
 * @param obj       number of results to get
 * @param callback  function to execute with the resulting data
 */
exports.createTalk = function(dburl, obj, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.insert(obj, function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};

/**
 * delete a talk by its id
 * @param dburl     database url string
 * @param id        talk id string
 * @param callback  function to execute with the resulting data
 */
exports.deleteTalk = function(dburl, id, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.remove({
            id: id
        }, function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};

/**
 * get a talk by its id
 * @param dburl     database url string
 * @param id        talk id string
 * @param callback  function to execute with the resulting data
 */
exports.get = function(dburl, id, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.findOne({
            id: id
        }, function(err, doc) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, doc);
        });
    });
};

/**
 * upvote a talk
 * @param dburl     database url string
 * @param id        Talk id
 * @param userid    User that upvotes the talk
 * @param callback  function to execute with the resulting data
 */
exports.upvote = function(dburl, id, userid, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.update({
            "id": id,
            "votes": {
                "$ne": userid
            }
        }, {
            "$inc": {
                "voteCount": 1
            },
            "$push": {
                "votes": userid
            }
        }, function(err, talk) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, talk);
        });
    });
};

/**
 * favorite a talk
 * @param dburl     database url string
 * @param id        Talk id
 * @param userid    User that favorites the talk
 * @param callback  function to execute with the resulting data
 */
exports.favorite = function(dburl, id, userid, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.update({
            "id": id,
            "favorites": {
                "$ne": userid
            }
        }, {
            "$inc": {
                "favoriteCount": 1
            },
            "$push": {
                "favorites": userid
            }
        }, function(err, talk) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, talk);
        });
    });
};

/**
 * unfavorite a talk
 * @param dburl     database url string
 * @param id        Talk id
 * @param userid    User that favorites the talk
 * @param callback  function to execute with the resulting data
 */
exports.unfavorite = function(dburl, id, userid, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.update({
            "id": id,
            "favorites": {
                "$in": [userid]
            }
        }, {
            "$inc": {
                "favoriteCount": -1
            },
            "$pull": {
                "favorites": userid
            }
        }, function(err, talk) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, talk);
        });
    });
};

/**
 * rank a a talk
 * Update raking score field
 * @param dburl     database url string
 * @param id        Talk Unique ID
 * @param score     Raking score
 * @param callback  function to execute with the resulting data
 */
exports.rank = function(dburl, id, score, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.update({
            "id": id
        }, {
            $set: {
                "ranking": score
            }
        }, function(err) {
            if (err) {
                return callback(err);
            }
            db.close();
            return callback(null);
        });
    });
};

/**
 * play a talk
 * Updates views field by 1.
 * @param dburl     database url string
 * @param slug      Talk slug
 * @param callback  function to execute with the resulting data
 */
exports.play = function(dburl, slug, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.findOne({
            "slug": slug
        }, function(err, talk) {
            if (err) {
                return callback(err, null);
            }
            talk.viewCount = talk.viewCount + 1;
            talks.update({
                "slug": slug
            }, {
                $inc: {
                    "viewCount": 1
                },
                $set: {
                    updated: Date.now()
                }
            }, function(err) {
                if (err) {
                    return callback(err, null);
                }
                db.close();
                return callback(null, talk);
            });
        });
    });
};

/**
 * get a talk by tag
 * @param dburl         database url string
 * @param tag           talk tag string
 * @param pageNumber    page number to get
 * @param callback      function to execute with the resulting data
 */
exports.getByTag = function(dburl, tag, pageNumber, callback) {
    "use strict";
    var conds = {
        tags: tag
    };
    var sort = {
        voteCount: -1,
        viewCount: -1
    };
    var quantity = 10;
    return searchTalks(dburl, conds, sort, quantity, pageNumber, callback);
};

/**
 * get a talk by its slug field
 * @param dburl         database url string
 * @param slug          talk slug string
 * @param callback      function to execute with the resulting data
 */
exports.getBySlug = function(dburl, slug, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.find({
            "slug": slug
        }).toArray(function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};

/**
 * get reltated talks from a list of tags
 * @param dburl     string      database url string
 * @param id        int         referenced talk
 * @param tags      Array       list of tag strings
 * @param callback  function    to execute with the resulting data
 */
exports.related = function(dburl, id, tags, quantity, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks
            .find({
                "tags": {
                    $in: tags
                },
                "id": {
                    "$ne": id
                }
            })
            .limit(quantity)
            .toArray(function(err, docs) {
                if (err) {
                    return callback(err, null);
                }
                db.close();
                return callback(null, docs);
            });
    });
};

/**
 * get a talk by its id
 * @param dburl     database url string
 * @param id        author id string
 * @param callback  function to execute with the resulting data
 */
exports.getByAuthorId = function(dburl, id, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.find({
            "author.id": id
        }).sort({
            "created": -1
        }).toArray(function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};

/**
 * get list of talks upvoted by an user
 * @param dburl     database url string
 * @param userid    author id string
 * @param callback  function to execute with the resulting data
 */
exports.getUpvotedByAuthorId = function(dburl, userid, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.find({
            "votes": {
                "$in": [userid]
            }
        }).sort({
            "created": -1
        }).toArray(function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};

/**
 * get list of talks favorited by an user
 * @param dburl     database url string
 * @param userid    author id string
 * @param callback  function to execute with the resulting data
 */
exports.getFavoritedByAuthorId = function(dburl, userid, callback) {
    "use strict";
    MongoClient.connect(dburl, function(err, db) {
        if (err) {
            return callback(err, null);
        }
        var talks = db.collection('talks');
        talks.find({
            "favorites": {
                "$in": [userid]
            }
        }).sort({
            "created": -1
        }).toArray(function(err, docs) {
            if (err) {
                return callback(err, null);
            }
            db.close();
            return callback(null, docs);
        });
    });
};
<|endoftext|>


<commit_before>// System modules.
var fs = require('fs');
var path = require('path');

// Third-party modules.
var et = require('elementtree');
var shelljs = require('shelljs');
var Q = require('q');

var utils = require('./utils');

// Returns a promise.
module.exports = exports = function postPrepareCommand() {
  var hasAndroid = fs.existsSync(path.join('platforms', 'android'));
  var hasIos = fs.existsSync(path.join('platforms', 'ios'));

  if (!fs.existsSync('platforms')) {
    return Q.reject('No platforms directory found. Please run script from the root of your project.');
  }

  var p = Q();
  if (hasAndroid) {
    p = p.then(function() { return postPrepareInternal('android'); });
  }
  if (hasIos) {
    p = p.then(function() { return postPrepareInternal('ios'); });
  }
  return p;
};

// Internal function called potentially multiple times to cover all platforms.
function postPrepareInternal(platform) {
  var root = utils.assetDirForPlatform(platform);

  /* Android asset packager ignores, by default, directories beginning with
     underscores. This can be fixed with an update to the project.properties
     file, but only when compiling with ant. There is a bug outstanding to
     fix this behaviour in Eclipse/ADT as well.

     References:
       https://code.google.com/p/android/issues/detail?id=5343
       https://code.google.com/p/android/issues/detail?id=41237
   */
  var badPath = path.join(utils.assetDirForPlatform(platform), '_locales');
  var betterPath = path.join(utils.assetDirForPlatform(platform), 'CCA_locales');
  var promise = Q();
  if (fs.existsSync(badPath)) {
    console.log('## Pre-processing _locales for ' + platform);
    fs.renameSync(badPath, betterPath);
    promise = Q.ninvoke(fs, 'readdir', betterPath)
    .then(function(files) {
      for (var i=0; i<files.length; i++) {
        var fullName = path.join(betterPath, files[i]);
        var adjustedFilename= files[i].replace('-', '_').toLowerCase();
        if (files[i] !== adjustedFilename) {
          var stats = fs.statSync(fullName);
          if (stats.isDirectory()) {
            fs.renameSync(fullName, path.join(betterPath, adjustedFilename));
          }
        }
      }
    });
  }

  return promise.then(function() {
    return require('./get-manifest')('www', platform);
  }).then(function(manifest) {
    if (!manifest || !manifest.icons) return;
    var iconMap = {};
    var iPhoneFiles = {
        'icon-40': true,
        'icon-small': true,
        'icon.png': true,
        'icon@2x': true,
        'icon-72': true,
        'icon-72@2x': true
    };
    var iPadFiles = {
        'icon-small': true,
        'icon-40': true,
        'icon-50': true,
        'icon-76': true,
        'icon': true,
        'icon@2x': true,
        'icon-72': true,
        'icon-72@2x': true
    };
    var infoPlistXml = null;
    var infoPlistPath = null;
    var iosIconDir = null;

    if (platform === "android") {
      iconMap = {
        "36": [path.join('res','drawable-ldpi','icon.png')],
        "48": [path.join('res','drawable-mdpi','icon.png')],
        "72": [path.join('res','drawable-hdpi','icon.png')],
        "96": [path.join('res','drawable-xhdpi','icon.png')],
        "144": [path.join('res','drawable-xxhdpi','icon.png')],
        "192": [path.join('res','drawable-xxxhdpi','icon.png')]
      };
    } else if (platform === "ios") {
      var platforms = require('cordova-lib').cordova_platforms;
      var parser = new platforms.ios.parser(path.join('platforms','ios'));
      iconMap = {
        "-1": [path.join(parser.originalName, 'Resources','icons','icon-60.png')], // this file exists in the template but isn't used.
        "29": [path.join(parser.originalName, 'Resources','icons','icon-small.png')],
        "40": [path.join(parser.originalName, 'Resources','icons','icon-40.png')],
        "50": [path.join(parser.originalName, 'Resources','icons','icon-50.png')],
        "57": [path.join(parser.originalName, 'Resources','icons','icon.png')],
        "58": [path.join(parser.originalName, 'Resources','icons','icon-small@2x.png')],
        "72": [path.join(parser.originalName, 'Resources','icons','icon-72.png')],
        "76": [path.join(parser.originalName, 'Resources','icons','icon-76.png')],
        "80": [path.join(parser.originalName, 'Resources','icons','icon-40@2x.png')],
        "100": [path.join(parser.originalName, 'Resources','icons','icon-50@2x.png')],
        "114": [path.join(parser.originalName, 'Resources','icons','icon@2x.png')],
        "120": [path.join(parser.originalName, 'Resources','icons','icon-60@2x.png')],
        "144": [path.join(parser.originalName, 'Resources','icons','icon-72@2x.png')],
        "152": [path.join(parser.originalName, 'Resources','icons','icon-76@2x.png')]
      };
      infoPlistPath = path.join('platforms', 'ios', parser.originalName, parser.originalName + '-Info.plist');
      infoPlistXml = et.parse(fs.readFileSync(infoPlistPath, 'utf-8'));
      iosIconDir = path.join(parser.originalName, 'Resources', 'icons');
    }
    function copyIcon(size, dstPath) {
      shelljs.mkdir('-p', path.dirname(dstPath));
      shelljs.cp('-f', path.join('www', utils.fixPathSlashes(manifest.icons[size])), dstPath);
      if (shelljs.error()) {
        console.log("Error copying " + size + "px icon file: " + shelljs.error());
      }
    }
    var missingIcons = [];
    var dstPath;
    if (iconMap) {
      //console.log('## Copying icons for ' + platform);
      for (var size in iconMap) {
        for (var i=0; i < iconMap[size].length; i++) {
          dstPath = path.join('platforms', platform, iconMap[size][i]);
          if (manifest.icons[size]) {
            //console.log("Copying " + size + "px icon file");
            copyIcon(size, dstPath);
          } else {
            missingIcons.push(dstPath);
          }
        }
      }
      // Find the largest icon.
      var bestSize = '0';
      for (size in manifest.icons) {
        bestSize = +size > +bestSize ? size : bestSize;
      }
      missingIcons.forEach(function(dstPath) {
        var imgName = path.basename(dstPath).replace(/\..*?$/, '');
        // Leave at least one icon.
        if (imgName != 'icon') {
          delete iPadFiles[imgName];
          delete iPhoneFiles[imgName];
        }
        // TODO: need to remove the iOS assets from the Xcode project file (ugh).
        if (platform == 'android') {
          shelljs.rm('-f', dstPath);
        } else if (platform == 'ios') {
          // Fill in all missing iOS icons with the largest resolution we have.
          copyIcon(bestSize, dstPath);
        }
      });
      // Use the largest icon as the default Android one.
      if (platform == 'android') {
        dstPath = path.join('platforms', platform, 'res', 'drawable', 'icon.png');
        copyIcon(bestSize, dstPath);
      }
      if (infoPlistXml) {
        var findArrayNode = function(key) {
          var foundNode = null;
          var foundKey = 0;
          infoPlistXml.iter('*', function(e) {
            if (foundKey === 0) {
              if (e.text == key) {
                foundKey = 1;
              }
            } else if (foundKey == 1) {
              if (e.text == 'CFBundleIconFiles') {
                foundKey = 2;
              }
            } else if (foundKey == 2) {
              if (e.tag == 'array') {
                foundNode = e;
                foundKey = 3;
              }
            }
          });
          return foundNode;
        };
        var setValues = function(key, vals) {
          var node = findArrayNode(key);
          node.clear();
          for (var imgName in vals) {
            et.SubElement(node, 'string').text = imgName;
          }
        };
        setValues('CFBundleIcons', iPhoneFiles);
        setValues('CFBundleIcons~ipad', iPadFiles);
        fs.writeFileSync(infoPlistPath, et.tostring(infoPlistXml.getroot(), {indent: 8}), 'utf8');
      }
    }
  })

  // Merge the manifests.
  .then(function() {
    return require('./get-manifest')('www', platform);
  }).then(function(manifest) {
    return Q.ninvoke(fs, 'writeFile', path.join(root, 'manifest.json'), JSON.stringify(manifest));
  })

  // Set the "other" version values if defined in the manifest.
  // CFBundleVersion on iOS and versionCode on Android.
  .then(function() {
    return require('./get-manifest')('www', platform);
  }).then(function(manifest) {
    // Android
    if (platform === 'android' && manifest) {
      if (manifest.versionCode) {
        var androidManifestPath = path.join('platforms', 'android', 'AndroidManifest.xml');
        var androidManifest = et.parse(fs.readFileSync(androidManifestPath, 'utf-8'));
        androidManifest.getroot().attrib["android:versionCode"] = manifest.versionCode;
        fs.writeFileSync(androidManifestPath, androidManifest.write({indent: 4}), 'utf-8');
      }
      if (manifest.short_name) {
        var stringsPath = path.join('platforms', 'android', 'res', 'values', 'strings.xml');
        var strings = et.parse(fs.readFileSync(stringsPath, 'utf-8'));
        strings.find('./string/[@name="launcher_name"]').text = manifest.short_name;
        fs.writeFileSync(stringsPath, strings.write({indent: 4}), 'utf-8');
      }
    }

    // On iOS it is customary to set CFBundleVersion = CFBundleShortVersionString
    // so if manifest.CFBundleVersion is not specifically set, we'll default to manifest.version
    if (platform === 'ios' && manifest && (manifest.version || manifest.CFBundleVersion)) {
      var platforms = require('cordova-lib').cordova_platforms;
      var parser = new platforms.ios.parser(path.join('platforms','ios'));
      var infoPlistPath = path.join('platforms', 'ios', parser.originalName, parser.originalName + '-Info.plist');
      var infoPlistXml = et.parse(fs.readFileSync(infoPlistPath, 'utf-8'));
      var theNode;
      var isFound = 0;

      // plist file format is pretty strange, we need the <string> node
      // immediately following <key>CFBundleVersion</key>
      // iterating over all the nodes.
      infoPlistXml.iter('*', function(e) {
        if (isFound === 0) {
          if (e.text == 'CFBundleVersion') {
            isFound = 1;
          }
        } else if (isFound == 1) {
          theNode = e;
          isFound = 2;
        }
      });

      theNode.text = manifest.CFBundleVersion || manifest.version;
      fs.writeFileSync(infoPlistPath, infoPlistXml.write({indent: 4}), 'utf-8');
    }
  });
}
<commit_msg>Updated Android Min SDK Version<commit_after>// System modules.
var fs = require('fs');
var path = require('path');

// Third-party modules.
var et = require('elementtree');
var shelljs = require('shelljs');
var Q = require('q');

var utils = require('./utils');

// Returns a promise.
module.exports = exports = function postPrepareCommand() {
  var hasAndroid = fs.existsSync(path.join('platforms', 'android'));
  var hasIos = fs.existsSync(path.join('platforms', 'ios'));

  if (!fs.existsSync('platforms')) {
    return Q.reject('No platforms directory found. Please run script from the root of your project.');
  }

  var p = Q();
  if (hasAndroid) {
    p = p.then(function() { return postPrepareInternal('android'); });
  }
  if (hasIos) {
    p = p.then(function() { return postPrepareInternal('ios'); });
  }
  return p;
};

// Internal function called potentially multiple times to cover all platforms.
function postPrepareInternal(platform) {
  var root = utils.assetDirForPlatform(platform);

  /* Android asset packager ignores, by default, directories beginning with
     underscores. This can be fixed with an update to the project.properties
     file, but only when compiling with ant. There is a bug outstanding to
     fix this behaviour in Eclipse/ADT as well.

     References:
       https://code.google.com/p/android/issues/detail?id=5343
       https://code.google.com/p/android/issues/detail?id=41237
   */
  var badPath = path.join(utils.assetDirForPlatform(platform), '_locales');
  var betterPath = path.join(utils.assetDirForPlatform(platform), 'CCA_locales');
  var promise = Q();
  if (fs.existsSync(badPath)) {
    console.log('## Pre-processing _locales for ' + platform);
    fs.renameSync(badPath, betterPath);
    promise = Q.ninvoke(fs, 'readdir', betterPath)
    .then(function(files) {
      for (var i=0; i<files.length; i++) {
        var fullName = path.join(betterPath, files[i]);
        var adjustedFilename= files[i].replace('-', '_').toLowerCase();
        if (files[i] !== adjustedFilename) {
          var stats = fs.statSync(fullName);
          if (stats.isDirectory()) {
            fs.renameSync(fullName, path.join(betterPath, adjustedFilename));
          }
        }
      }
    });
  }

  return promise.then(function() {
    return require('./get-manifest')('www', platform);
  }).then(function(manifest) {
    if (!manifest || !manifest.icons) return;
    var iconMap = {};
    var iPhoneFiles = {
        'icon-40': true,
        'icon-small': true,
        'icon.png': true,
        'icon@2x': true,
        'icon-72': true,
        'icon-72@2x': true
    };
    var iPadFiles = {
        'icon-small': true,
        'icon-40': true,
        'icon-50': true,
        'icon-76': true,
        'icon': true,
        'icon@2x': true,
        'icon-72': true,
        'icon-72@2x': true
    };
    var infoPlistXml = null;
    var infoPlistPath = null;
    var iosIconDir = null;

    if (platform === "android") {
      iconMap = {
        "36": [path.join('res','drawable-ldpi','icon.png')],
        "48": [path.join('res','drawable-mdpi','icon.png')],
        "72": [path.join('res','drawable-hdpi','icon.png')],
        "96": [path.join('res','drawable-xhdpi','icon.png')],
        "144": [path.join('res','drawable-xxhdpi','icon.png')],
        "192": [path.join('res','drawable-xxxhdpi','icon.png')]
      };
    } else if (platform === "ios") {
      var platforms = require('cordova-lib').cordova_platforms;
      var parser = new platforms.ios.parser(path.join('platforms','ios'));
      iconMap = {
        "-1": [path.join(parser.originalName, 'Resources','icons','icon-60.png')], // this file exists in the template but isn't used.
        "29": [path.join(parser.originalName, 'Resources','icons','icon-small.png')],
        "40": [path.join(parser.originalName, 'Resources','icons','icon-40.png')],
        "50": [path.join(parser.originalName, 'Resources','icons','icon-50.png')],
        "57": [path.join(parser.originalName, 'Resources','icons','icon.png')],
        "58": [path.join(parser.originalName, 'Resources','icons','icon-small@2x.png')],
        "72": [path.join(parser.originalName, 'Resources','icons','icon-72.png')],
        "76": [path.join(parser.originalName, 'Resources','icons','icon-76.png')],
        "80": [path.join(parser.originalName, 'Resources','icons','icon-40@2x.png')],
        "100": [path.join(parser.originalName, 'Resources','icons','icon-50@2x.png')],
        "114": [path.join(parser.originalName, 'Resources','icons','icon@2x.png')],
        "120": [path.join(parser.originalName, 'Resources','icons','icon-60@2x.png')],
        "144": [path.join(parser.originalName, 'Resources','icons','icon-72@2x.png')],
        "152": [path.join(parser.originalName, 'Resources','icons','icon-76@2x.png')]
      };
      infoPlistPath = path.join('platforms', 'ios', parser.originalName, parser.originalName + '-Info.plist');
      infoPlistXml = et.parse(fs.readFileSync(infoPlistPath, 'utf-8'));
      iosIconDir = path.join(parser.originalName, 'Resources', 'icons');
    }
    function copyIcon(size, dstPath) {
      shelljs.mkdir('-p', path.dirname(dstPath));
      shelljs.cp('-f', path.join('www', utils.fixPathSlashes(manifest.icons[size])), dstPath);
      if (shelljs.error()) {
        console.log("Error copying " + size + "px icon file: " + shelljs.error());
      }
    }
    var missingIcons = [];
    var dstPath;
    if (iconMap) {
      //console.log('## Copying icons for ' + platform);
      for (var size in iconMap) {
        for (var i=0; i < iconMap[size].length; i++) {
          dstPath = path.join('platforms', platform, iconMap[size][i]);
          if (manifest.icons[size]) {
            //console.log("Copying " + size + "px icon file");
            copyIcon(size, dstPath);
          } else {
            missingIcons.push(dstPath);
          }
        }
      }
      // Find the largest icon.
      var bestSize = '0';
      for (size in manifest.icons) {
        bestSize = +size > +bestSize ? size : bestSize;
      }
      missingIcons.forEach(function(dstPath) {
        var imgName = path.basename(dstPath).replace(/\..*?$/, '');
        // Leave at least one icon.
        if (imgName != 'icon') {
          delete iPadFiles[imgName];
          delete iPhoneFiles[imgName];
        }
        // TODO: need to remove the iOS assets from the Xcode project file (ugh).
        if (platform == 'android') {
          shelljs.rm('-f', dstPath);
        } else if (platform == 'ios') {
          // Fill in all missing iOS icons with the largest resolution we have.
          copyIcon(bestSize, dstPath);
        }
      });
      // Use the largest icon as the default Android one.
      if (platform == 'android') {
        dstPath = path.join('platforms', platform, 'res', 'drawable', 'icon.png');
        copyIcon(bestSize, dstPath);
      }
      if (infoPlistXml) {
        var findArrayNode = function(key) {
          var foundNode = null;
          var foundKey = 0;
          infoPlistXml.iter('*', function(e) {
            if (foundKey === 0) {
              if (e.text == key) {
                foundKey = 1;
              }
            } else if (foundKey == 1) {
              if (e.text == 'CFBundleIconFiles') {
                foundKey = 2;
              }
            } else if (foundKey == 2) {
              if (e.tag == 'array') {
                foundNode = e;
                foundKey = 3;
              }
            }
          });
          return foundNode;
        };
        var setValues = function(key, vals) {
          var node = findArrayNode(key);
          node.clear();
          for (var imgName in vals) {
            et.SubElement(node, 'string').text = imgName;
          }
        };
        setValues('CFBundleIcons', iPhoneFiles);
        setValues('CFBundleIcons~ipad', iPadFiles);
        fs.writeFileSync(infoPlistPath, et.tostring(infoPlistXml.getroot(), {indent: 8}), 'utf8');
      }
    }
  })

  // Update Android minSdkVersion.
  .then(function() {
    if (platform === 'android') {
      var iceCreamSandwichVersion = '14';
      var androidManifestPath = path.join('platforms', 'android', 'AndroidManifest.xml');
      var androidManifest = et.parse(fs.readFileSync(androidManifestPath, 'utf-8'));
      androidManifest.find('./uses-sdk/').attrib["android:minSdkVersion"] = iceCreamSandwichVersion;
      fs.writeFileSync(androidManifestPath, androidManifest.write({indent: 4}), 'utf-8');
    }
  })

  // Merge the manifests.
  .then(function() {
    return require('./get-manifest')('www', platform);
  }).then(function(manifest) {
    return Q.ninvoke(fs, 'writeFile', path.join(root, 'manifest.json'), JSON.stringify(manifest));
  })

  // Set the "other" version values if defined in the manifest.
  // CFBundleVersion on iOS and versionCode on Android.
  .then(function() {
    return require('./get-manifest')('www', platform);
  }).then(function(manifest) {
    // Android
    if (platform === 'android' && manifest) {
      if (manifest.versionCode) {
        var androidManifestPath = path.join('platforms', 'android', 'AndroidManifest.xml');
        var androidManifest = et.parse(fs.readFileSync(androidManifestPath, 'utf-8'));
        androidManifest.getroot().attrib["android:versionCode"] = manifest.versionCode;
        fs.writeFileSync(androidManifestPath, androidManifest.write({indent: 4}), 'utf-8');
      }
      if (manifest.short_name) {
        var stringsPath = path.join('platforms', 'android', 'res', 'values', 'strings.xml');
        var strings = et.parse(fs.readFileSync(stringsPath, 'utf-8'));
        strings.find('./string/[@name="launcher_name"]').text = manifest.short_name;
        fs.writeFileSync(stringsPath, strings.write({indent: 4}), 'utf-8');
      }
    }

    // On iOS it is customary to set CFBundleVersion = CFBundleShortVersionString
    // so if manifest.CFBundleVersion is not specifically set, we'll default to manifest.version
    if (platform === 'ios' && manifest && (manifest.version || manifest.CFBundleVersion)) {
      var platforms = require('cordova-lib').cordova_platforms;
      var parser = new platforms.ios.parser(path.join('platforms','ios'));
      var infoPlistPath = path.join('platforms', 'ios', parser.originalName, parser.originalName + '-Info.plist');
      var infoPlistXml = et.parse(fs.readFileSync(infoPlistPath, 'utf-8'));
      var theNode;
      var isFound = 0;

      // plist file format is pretty strange, we need the <string> node
      // immediately following <key>CFBundleVersion</key>
      // iterating over all the nodes.
      infoPlistXml.iter('*', function(e) {
        if (isFound === 0) {
          if (e.text == 'CFBundleVersion') {
            isFound = 1;
          }
        } else if (isFound == 1) {
          theNode = e;
          isFound = 2;
        }
      });

      theNode.text = manifest.CFBundleVersion || manifest.version;
      fs.writeFileSync(infoPlistPath, infoPlistXml.write({indent: 4}), 'utf-8');
    }
  });
}
<|endoftext|>


<commit_before>(function() {
    /* global cooMatchCommand */
    /* global cooCreateScope */
    /* global cooPushScopeVariable */
    /* global cooGetScopeVariablesDecl */
    /* global cooGetScopeRet */
    /* global COO_INTERNAL_VARIABLE_RET */
    /* global cooValueToJS */
    /* global cooAssertNotValuePusher */

    function setProcess(cmd) {
        if (!cmd.parent) {
            return cmd.parts[0];
        }

        return cooMatchCommand(cmd, {
            'SET': {
                '': {
                    '@': function() {
                        // SET identifier
                        //     ...
                        cooAssertNotValuePusher(cmd);

                        cmd.hasSubblock = true;
                        cmd.valueRequired = true;

                        cooCreateScope(cmd);
                        cooPushScopeVariable(cmd.parent, cmd.parts[1].value);

                        cmd.getCodeBefore = function() {
                            if (!cmd.children.length) {
                                return;
                            }

                            var ret = [];

                            if (cmd.valuePusher) {
                                ret.push(COO_INTERNAL_VARIABLE_RET);
                                ret.push('.push(');
                            }

                            ret.push(cmd.parts[1].value);
                            ret.push(' = CooCooRet((function() {');
                            ret.push(cooGetScopeVariablesDecl(cmd));

                            return ret.join('');
                        };

                        cmd.getCodeAfter = function() {
                            var ret = [];

                            ret.push(cooGetScopeRet(cmd));
                            ret.push('}).call(this');

                            if (cmd.valuePusher) {
                                ret.push(')');
                            }

                            ret.push(')).valueOf();');

                            return ret.join('');
                        };
                    },

                    '(': function() {
                        // SET identifier (expr)
                        var name = cmd.parts[1].value,
                            val = cmd.parts[2];

                        cooPushScopeVariable(cmd, name);

                        cmd.getCodeBefore = function() {
                            var ret = [];

                            if (cmd.valuePusher) {
                                ret.push(COO_INTERNAL_VARIABLE_RET);
                                ret.push('.push(');
                            }

                            ret.push(name);
                            ret.push(' = ');
                            ret.push(cooValueToJS(cmd, val));

                            if (cmd.valuePusher) {
                                ret.push(')');
                            }

                            ret.push(';');

                            return ret.join('');
                        };
                    }
                }
            }
        });
    }

    CooCoo.cmd.SET = {
        process: setProcess,
        arrange: null
    };
})();
<commit_msg>Incorrect empty SET tail fix.<commit_after>(function() {
    /* global cooMatchCommand */
    /* global cooCreateScope */
    /* global cooPushScopeVariable */
    /* global cooGetScopeVariablesDecl */
    /* global cooGetScopeRet */
    /* global COO_INTERNAL_VARIABLE_RET */
    /* global cooValueToJS */
    /* global cooAssertNotValuePusher */

    function setProcess(cmd) {
        if (!cmd.parent) {
            return cmd.parts[0];
        }

        return cooMatchCommand(cmd, {
            'SET': {
                '': {
                    '@': function() {
                        // SET identifier
                        //     ...
                        cooAssertNotValuePusher(cmd);

                        cmd.hasSubblock = true;
                        cmd.valueRequired = true;

                        cooCreateScope(cmd);
                        cooPushScopeVariable(cmd.parent, cmd.parts[1].value);

                        cmd.getCodeBefore = function() {
                            if (!cmd.children.length) {
                                return;
                            }

                            var ret = [];

                            if (cmd.valuePusher) {
                                ret.push(COO_INTERNAL_VARIABLE_RET);
                                ret.push('.push(');
                            }

                            ret.push(cmd.parts[1].value);
                            ret.push(' = CooCooRet((function() {');
                            ret.push(cooGetScopeVariablesDecl(cmd));

                            return ret.join('');
                        };

                        cmd.getCodeAfter = function() {
                            if (!cmd.children.length) {
                                return;
                            }

                            var ret = [];

                            ret.push(cooGetScopeRet(cmd));
                            ret.push('}).call(this');

                            if (cmd.valuePusher) {
                                ret.push(')');
                            }

                            ret.push(')).valueOf();');

                            return ret.join('');
                        };
                    },

                    '(': function() {
                        // SET identifier (expr)
                        var name = cmd.parts[1].value,
                            val = cmd.parts[2];

                        cooPushScopeVariable(cmd, name);

                        cmd.getCodeBefore = function() {
                            var ret = [];

                            if (cmd.valuePusher) {
                                ret.push(COO_INTERNAL_VARIABLE_RET);
                                ret.push('.push(');
                            }

                            ret.push(name);
                            ret.push(' = ');
                            ret.push(cooValueToJS(cmd, val));

                            if (cmd.valuePusher) {
                                ret.push(')');
                            }

                            ret.push(';');

                            return ret.join('');
                        };
                    }
                }
            }
        });
    }

    CooCoo.cmd.SET = {
        process: setProcess,
        arrange: null
    };
})();
<|endoftext|>


<commit_before>var path = require('path'),
    fs = require('fs'),
    config = require('./config')(),
    reporter = require('./reporter'),
    exec = require('child_process').exec,
    spawn = require('child_process').spawn,
    tty = require('tty');

var Task = function(argv) {
    'use strict';

    var proto;

    this.opts = argv;
    this.args = argv._.slice(1);
    this.reporter = reporter;

    try {
        this.customRun = require(path.join(config.cwd, 'pas.json')).tasks[argv._[0]];
        if (this.customRun) {
            return;
        }
    } catch(e) {
        this.customRun = null;
    }

    var splitted = argv._[0].split(':'),
        taskName = splitted[0],
        pathSuffix = splitted.join('/');

    var TASKS = task.getRegisteredTasks();
    if (TASKS[argv._[0]]) {
        proto = TASKS[argv._[0]];
    } else {
        var protoPaths = [
            path.join(config.pluginHome, 'pas-' + taskName, 'tasks', splitted[1] || 'index'),
            path.join(config.cwd, 'node_modules', 'pas-' + taskName, 'tasks', splitted[1] || 'index')
        ];

        var es = [];
        var found = protoPaths.some(function(protoPath) {
            try {
                proto = require(protoPath);
                return true;
            } catch(e) {
                es.push(e);
                return;
            }
        });

        if (!found) {
            throw new Error('Task "' + argv._[0] + '" not found or error');
        }
    }

    if (typeof proto === 'function') {
        this.exec = proto;
    } else {
        for(var i in proto) {
            this[i] = proto[i];
        }
    }
};

Task.prototype.require = function(name) {
    'use strict';

    return require('./' + name);
};

Task.prototype.report = function(type) {
    'use strict';

    var args = arguments; // Array.prototype.slice.call(arguments, 1);
    this.reporter.print.apply(this.reporter, args);
};

Task.prototype.run = function() {
    'use strict';

    return this.exec.apply(this, this.args);
};

Task.prototype.exec = function() {
    'use strict';

    if (!this.customRun) {
        throw new Error('No custom taskRun or invalid task');
    }

    this.report('message', 'Running: %s', typeof this.customRun === 'string' ? this.customRun : (this.customRun.join(' ') + ' (spawned)'));

    return new Promise(function(resolve, reject) {
        var onOut = function(line) {
            this.report('message', '    | %s', line);
        }.bind(this);

        var onErr = function(line) {
            this.report('message', '   e| %s', line);
        }.bind(this);

        if (typeof this.customRun === 'string') {
            exec(this.customRun, function(err, stdout, stderr) {
                if (err) {
                    return reject(err);
                }

                stdout = stdout.split('\n');
                if (stdout.length > 1) {
                    stdout.forEach(onOut);
                }

                stderr = stderr.split('\n');
                if (stderr.length > 1) {
                    stderr.forEach(onErr);
                }

            }.bind(this));
        } else {
            var onIn = function(c) {
                taskRun.stdin.write(c);
            };

            var taskRun = spawn(this.customRun[0], this.customRun.slice(1), {stdio:'inherit'});
            // process.stdin.resume();
            // process.stdin.on('data', onIn);

            // taskRun.stdout.on('data', function(c) {
            //     process.stdout.write(c);
            // });
            // taskRun.stderr.on('data', function(c) {
            //     process.stderr.write(c);
            // });

            // process.stdin.setRawMode(true);

            taskRun.on('exit', function(code) {
                // process.stdin.setRawMode(false);
                // process.stdin.pause();
                // process.stdin.removeListener('data', onIn);
                //
                if (code === 0 || code === '0') {
                    this.report('message', 'Exit successfully');
                    resolve();
                } else {
                    reject(new Error('Exit with error code: ' + code));
                }
            }.bind(this));
        }
    }.bind(this));
};

var getTask = function(argv) {
    'use strict';

    return new Task(argv);
};

var task = function(argv) {
    'use strict';

    return Promise.resolve(getTask(argv).run());
};

task.Task = Task;
task.get = getTask;
task.getRegisteredTasks = function() {
    return {
        'config': require('./tasks/config'),
        'deps': require('./tasks/deps'),
        'help': require('./tasks/help'),
        'info': require('./tasks/info'),
        'init': require('./tasks/init'),
        'install': require('./tasks/install'),
        'link': require('./tasks/link'),
        'plugin': require('./tasks/plugin'),
        'plugin:install': require('./tasks/plugin/install'),
        'pull': require('./tasks/pull'),
        'search': require('./tasks/search'),
        'uninstall': require('./tasks/uninstall'),
        'unlink': require('./tasks/unlink'),
        'update': require('./tasks/update'),
        'module': require('./tasks/module'),
        'module:add': require('./tasks/module/add'),
    };
};
module.exports = task;<commit_msg>ENABLED multi line custom task<commit_after>var path = require('path'),
    fs = require('fs'),
    config = require('./config')(),
    reporter = require('./reporter'),
    exec = require('child_process').exec,
    spawn = require('child_process').spawn,
    tty = require('tty');

var Task = function(argv) {
    'use strict';

    var proto;

    this.opts = argv;
    this.args = argv._.slice(1);
    this.reporter = reporter;

    try {
        this.customRun = require(path.join(config.cwd, 'pas.json')).tasks[argv._[0]];
        if (this.customRun) {
            return;
        }
    } catch(e) {
        this.customRun = null;
    }

    var splitted = argv._[0].split(':'),
        taskName = splitted[0],
        pathSuffix = splitted.join('/');

    var TASKS = task.getRegisteredTasks();
    if (TASKS[argv._[0]]) {
        proto = TASKS[argv._[0]];
    } else {
        var protoPaths = [
            path.join(config.pluginHome, 'pas-' + taskName, 'tasks', splitted[1] || 'index'),
            path.join(config.cwd, 'node_modules', 'pas-' + taskName, 'tasks', splitted[1] || 'index')
        ];

        var es = [];
        var found = protoPaths.some(function(protoPath) {
            try {
                proto = require(protoPath);
                return true;
            } catch(e) {
                es.push(e);
                return;
            }
        });

        if (!found) {
            throw new Error('Task "' + argv._[0] + '" not found or error');
        }
    }

    if (typeof proto === 'function') {
        this.exec = proto;
    } else {
        for(var i in proto) {
            this[i] = proto[i];
        }
    }
};

Task.prototype.require = function(name) {
    'use strict';

    return require('./' + name);
};

Task.prototype.report = function(type) {
    'use strict';

    var args = arguments; // Array.prototype.slice.call(arguments, 1);
    this.reporter.print.apply(this.reporter, args);
};

Task.prototype.run = function() {
    'use strict';

    return this.exec.apply(this, this.args);
};

Task.prototype.exec = function() {
    'use strict';

    if (!this.customRun) {
        throw new Error('No custom taskRun or invalid task');
    }

    var onOut = function(line) {
        this.report('message', '%s', line);
    }.bind(this);

    var onErr = function(line) {
        this.report('message', '%s', line);
    }.bind(this);

    var execPromise = function(cmd) {
        return new Promise(function(resolve, reject) {
            this.report('message', '-> %s', cmd);

            exec(cmd, function(err, stdout, stderr) {
                if (err) {
                    return reject(err);
                }

                stdout = stdout.trim().split('\n');
                if (stdout.length > 0 && stdout[0] !== '') {
                    stdout.forEach(onOut);
                }

                stderr = stderr.trim().split('\n');
                if (stderr.length > 0 && stderr[0] !== '') {
                    stderr.forEach(onErr);
                }

                resolve();

            }.bind(this));
        }.bind(this));
    }.bind(this);

    if (typeof this.customRun === 'string') {
        return execPromise(this.customRun);
    } else {
        var promise = Promise.resolve();

        this.customRun.forEach(function(cmd) {
            if (typeof cmd === 'string') {
                promise = promise.then(function() {
                    return execPromise(cmd);
                }.bind(this));
            } else {
                promise = promise.then(function() {
                    return new Promise(function(resolve, reject) {
                        this.report('message', '-> %s', cmd);

                        var taskRun = spawn(cmd[0], cmd.slice(1), {stdio:'inherit'});

                        taskRun.on('exit', function(code) {
                            if (code === 0 || code === '0') {
                                this.report('message', 'Exit successfully');
                                resolve();
                            } else {
                                reject(new Error('Exit with error code: ' + code));
                            }
                        }.bind(this));
                    }.bind(this));
                }.bind(this));
            }
        }.bind(this));

        return promise;
    }
};

var getTask = function(argv) {
    'use strict';

    return new Task(argv);
};

var task = function(argv) {
    'use strict';

    return Promise.resolve(getTask(argv).run());
};

task.Task = Task;
task.get = getTask;
task.getRegisteredTasks = function() {
    return {
        'config': require('./tasks/config'),
        'deps': require('./tasks/deps'),
        'help': require('./tasks/help'),
        'info': require('./tasks/info'),
        'init': require('./tasks/init'),
        'install': require('./tasks/install'),
        'link': require('./tasks/link'),
        'plugin': require('./tasks/plugin'),
        'plugin:install': require('./tasks/plugin/install'),
        'pull': require('./tasks/pull'),
        'search': require('./tasks/search'),
        'uninstall': require('./tasks/uninstall'),
        'unlink': require('./tasks/unlink'),
        'update': require('./tasks/update'),
        'module': require('./tasks/module'),
        'module:add': require('./tasks/module/add'),
    };
};
module.exports = task;<|endoftext|>


<commit_before>import sortify from "./sortify"; //tnr TODO: export this from json.sortify when https://github.com/ThomasR/JSON.sortify/issues/11 is resolved
import isNumber from "lodash/isNumber";
import mathExpressionEvaluator from "math-expression-evaluator";
import cloneDeep from "lodash/cloneDeep";
import deepEqual from "deep-equal";
import React from "react";
import { Field } from "redux-form";
import Select from "react-select";
import Uploader from "./Uploader";

import "./style.css";
import {
  InputGroup,
  NumericInput,
  Intent,
  Radio,
  RadioGroup,
  Checkbox,
  EditableText,
  Tooltip,
  Position,
  Switch
} from "@blueprintjs/core";

import { DateInput, DateRangeInput } from "@blueprintjs/datetime";

function getIntent({ showErrorIfUntouched, meta: { touched, error } }) {
  return (touched || showErrorIfUntouched) && error ? Intent.DANGER : "";
}

function getIntentClass({ showErrorIfUntouched, meta: { touched, error } }) {
  return (touched || showErrorIfUntouched) && error ? "pt-intent-danger" : "";
}

function removeUnwantedProps(props) {
  let cleanedProps = { ...props };
  delete cleanedProps.className;
  delete cleanedProps.units;
  delete cleanedProps.showErrorIfUntouched;
  delete cleanedProps.onChange;
  delete cleanedProps.onFieldSubmit;
  delete cleanedProps.onBlur;
  delete cleanedProps.intent;
  delete cleanedProps.intentClass;
  delete cleanedProps.meta;
  delete cleanedProps.defaultValue;
  delete cleanedProps.tabIndex;
  delete cleanedProps.tooltipError;
  delete cleanedProps.tooltipProps;
  if (cleanedProps.inputClassName) {
    cleanedProps.className = cleanedProps.inputClassName;
    delete cleanedProps.inputClassName;
  }
  return cleanedProps;
}

class AbstractInput extends React.Component {
  componentWillMount() {
    const {
      meta: { dispatch, form },
      defaultValue,
      input: { name, value }
    } = this.props;
    !value &&
      defaultValue !== undefined &&
      dispatch({
        type: "@@redux-form/CHANGE",
        meta: {
          form,
          field: name
        },
        payload: defaultValue
      });
  }

  componentWillReceiveProps({
    meta: { dispatch, form },
    defaultValue,
    input: { name, value }
  }) {
    const { defaultValue: oldDefaultValue } = this.props;
    if (!value && !deepEqual(defaultValue, oldDefaultValue)) {
      dispatch({
        type: "@@redux-form/CHANGE",
        meta: {
          form,
          field: name
        },
        payload: defaultValue
      });
    }
  }

  render() {
    const {
      children,
      tooltipProps,
      tooltipError,
      label,
      className,
      showErrorIfUntouched,
      meta,
      noOuterLabel
    } = this.props;
    const { touched, error } = meta;
    const showError = (touched || showErrorIfUntouched) && error;

    const componentToWrap = tooltipError ? (
      <Tooltip
        isDisabled={!showError}
        intent={Intent.DANGER}
        content={error}
        position={Position.TOP}
        {...tooltipProps}
      >
        {children}
      </Tooltip>
    ) : (
      children
    );

    return (

        {label && !noOuterLabel && {label}}
        {componentToWrap}
        {!tooltipError &&
        showError && (

            {error}

        )}

    );
  }
}

export const renderBlueprintDateInput = props => {
  const { input, intent, onFieldSubmit, ...rest } = props;
  return (
    <DateInput
      {...removeUnwantedProps(rest)}
      intent={intent}
      format="MM/DD/YYYY"
      {...input}
      onChange={function(selectedDate) {
        input.onChange(selectedDate);
        onFieldSubmit(selectedDate);
      }}
    />
  );
};

export const renderBlueprintDateRangeInput = props => {
  const { input, intent, onFieldSubmit, ...rest } = props;
  return (
    <DateRangeInput
      {...removeUnwantedProps(rest)}
      intent={intent}
      format="MM/DD/YYYY"
      {...input}
      onChange={function(selectedDate) {
        input.onChange(selectedDate);
        onFieldSubmit(selectedDate);
      }}
    />
  );
};

export const renderBlueprintInput = props => {
  const { input, intent, onFieldSubmit, ...rest } = props;
  return (
    <InputGroup
      {...removeUnwantedProps(rest)}
      intent={intent}
      {...input}
      onKeyDown={function(e) {
        if (e.key === "Enter") {
          onFieldSubmit(e.target.value, { enter: true }, e);
        }
      }}
      onBlur={function(e, val) {
        input.onBlur(e, val);
        onFieldSubmit(e.target ? e.target.value : val, { blur: true }, e);
      }}
    />
  );
};

export const renderBlueprintCheckbox = props => {
  const { input, label, onFieldSubmit, ...rest } = props;
  return (
    <Checkbox
      {...removeUnwantedProps(rest)}
      {...input}
      checked={input.value}
      label={label}
      onChange={function(e, val) {
        input.onChange(e, val);
        onFieldSubmit(e.target ? e.target.value : val);
      }}
    />
  );
};

export const renderBlueprintSwitch = props => {
  const { input, label, onFieldSubmit, ...rest } = props;
  return (
    <Switch
      {...removeUnwantedProps(rest)}
      {...input}
      checked={input.value}
      label={label}
      onChange={function(e, val) {
        input.onChange(e, val);
        onFieldSubmit(e.target ? e.target.value : val);
      }}
    />
  );
};

export const renderFileUpload = props => {
  const { input, onFieldSubmit, ...rest } = props;
  return (
    <Uploader
      fileList={input.value}
      onFieldSubmit={onFieldSubmit}
      {...rest}
      onChange={input.onChange}
    />
  );
};

export const renderBlueprintTextarea = props => {
  const { input, intentClass, inputClassName, onFieldSubmit, ...rest } = props;
  return (
    <textarea
      {...removeUnwantedProps(rest)}
      className={`${intentClass || ""} ${inputClassName ||
        ""} pt-input pt-fill`}
      {...input}
      onBlur={function(e, val) {
        input.onBlur(e, val);
        onFieldSubmit(e.target ? e.target.value : val, { blur: true }, e);
      }}
      onKeyDown={function(e) {
        if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
          onFieldSubmit(e.target.value, { cmdEnter: true }, e);
        }
      }}
    />
  );
};

export const renderBlueprintEditableText = props => {
  const { input, onFieldSubmit, ...rest } = props;
  return (
    <EditableText
      {...removeUnwantedProps(rest)}
      {...input}
      onConfirm={function(value) {
        input.onBlur && input.onBlur(value);
        onFieldSubmit(value);
      }}
    />
  );
};

export const renderReactSelect = props => {
  // spreading input not working, grab the values needed instead
  const {
    async,
    input: { value, onChange },
    hideValue,
    options,
    onFieldSubmit,
    ...rest
  } = props;
  const optsToUse =
    options &&
    options.map(function(opt) {
      if (typeof opt === "string") {
        return { label: opt, value: opt };
      } else if (isNumber(opt)) return { label: opt.toString(), value: opt };
      return opt;
    });
  const valueToUse = //here we're coercing json values into an object with {label,value} because react-select does not seem to recognize the json value directly
    !Array.isArray(value) && typeof value === "object"
      ? optsToUse.find(obj => {
          return deepEqual(obj.value, value);
        })
      : Array.isArray(value)
        ? value.map(val => {
            return optsToUse
              ? optsToUse.find(obj => {
                  return deepEqual(obj.value, val);
                })
              : val;
          })
        : value;

  const propsToUse = {
    ...removeUnwantedProps(rest),
    options: optsToUse,
    value: valueToUse,

    onChange(valOrVals, ...rest) {
      const valToPass = Array.isArray(valOrVals)
        ? valOrVals.map(function(val) {
            return val.value;
          })
        : valOrVals ? valOrVals.value : "";
      onChange(valToPass, ...rest);
      onFieldSubmit(valToPass);
    }
  };
  return async ? <Select.Async {...propsToUse} /> : <Select {...propsToUse} />;
};

export const renderSelect = props => {
  // spreading input not working, grab the values needed instead
  const {
    input: { value, onChange },
    hideValue,
    placeholder,
    onFieldSubmit,
    options,
    ...rest
  } = props;
  return (

      <select
        {...removeUnwantedProps(rest)}
        value={
          placeholder && value === "" ? (
            "__placeholder__"
          ) : typeof value !== "string" ? (
            sortify(value) //deterministically sort and stringify the object/number coming in because select fields only support string values
          ) : (
            value
          )
        }
        {...(hideValue ? { value: "" } : {})}
        onChange={function(e) {
          let val = e.target.value;
          try {
            val = JSON.parse(e.target.value); //try to json parse the string coming in
          } catch (e) {}
          onChange(val);
          onFieldSubmit(val);
        }}
      >
        {placeholder && (
          <option value="__placeholder__" disabled hidden>
            {placeholder}
          </option>
        )}
        {options.map(function(opt, index) {
          let label, value;
          if (typeof opt === "string") {
            //support passing opts like: ['asdf','awfw']
            label = opt;
            value = opt;
          } else if (isNumber(opt)) {
            //support passing opts like: [1,2,3,4]
            label = opt.toString();
            value = opt;
          } else if (Array.isArray(opt)) {
            throw new Error(
              "the option coming in should be an object, not an array!"
            );
          } else {
            //support passing opts the normal way [{label: 'opt1', value: 'hey'}]
            label = opt.label;
            value = opt.value;
          }
          return (
            <option
              key={index}
              value={
                typeof value !== "string" ? (
                  sortify(value) //deterministically sort and stringify the object/number coming in because select fields only support string values
                ) : (
                  value
                )
              }
            >
              {label}
            </option>
          );
        })}
      </select>

  );
};

export const renderBlueprintNumericInput = props => {
  const {
    input,
    hideValue,
    intent,
    inputClassName,
    onFieldSubmit,
    ...rest
  } = props;
  function handleBlurOrButtonClick(stringVal) {
    try {
      const num = mathExpressionEvaluator.eval(stringVal);
      input.onBlur(num);
      onFieldSubmit(num);
    } catch (e) {
      input.onBlur("");
      onFieldSubmit("");
    }
  }
  return (
    <NumericInput
      value={input.value}
      intent={intent}
      {...removeUnwantedProps(rest)}
      {...(hideValue ? { value: "" } : {})}
      className={`pt-fill ${inputClassName || ""}`}
      onValueChange={(numericVal, stringVal) => {
        // needed for redux form to change value
        input.onChange(stringVal);
      }}
      onButtonClick={function(numericVal, stringVal) {
        handleBlurOrButtonClick(stringVal);
      }}
      onBlur={function(e) {
        handleBlurOrButtonClick(e.target.value);
      }}
    />
  );
};

export const renderBlueprintRadioGroup = ({
  input,
  options,
  onFieldSubmit,
  ...rest
}) => {
  return (
    <RadioGroup
      {...input}
      selectedValue={input.value}
      onChange={function(e, val, ...args) {
        input.onChange(e, val, ...args);
        onFieldSubmit(e.target ? e.target.value : val);
      }}
    >
      {options.map(function({ label, value }, index) {
        return (
          <Radio
            {...removeUnwantedProps(rest)}
            key={index}
            value={value}
            label={label}
          />
        );
      })}
    </RadioGroup>
  );
};

function generateField(component, opts) {
  const compWithDefaultVal = withAbstractWrapper(component, opts);
  return function FieldMaker({ name, onFieldSubmit = () => {}, ...rest }) {
    // function onFieldSubmit(e,val) {
    //   _onFieldSubmit && _onFieldSubmit(e.target ? e.target.value : val)
    // }
    return (
      <Field
        onFieldSubmit={onFieldSubmit}
        name={name}
        component={compWithDefaultVal}
        {...rest}
      />
    );
  };
}

export const withAbstractWrapper = (ComponentToWrap, opts = {}) => {
  return props => {
    let defaultProps = {
      ...props,
      intent: getIntent(props),
      intentClass: getIntentClass(props)
    };
    return (
      <AbstractInput {...{ ...opts, ...props }}>
        <ComponentToWrap {...defaultProps} />
      </AbstractInput>
    );
  };
};

export const InputField = generateField(renderBlueprintInput);
export const FileUploadField = generateField(renderFileUpload);
export const DateInputField = generateField(renderBlueprintDateInput);
export const DateRangeInputField = generateField(renderBlueprintDateRangeInput);
export const CheckboxField = generateField(renderBlueprintCheckbox, {
  noOuterLabel: true
});
export const SwitchField = generateField(renderBlueprintSwitch, {
  noOuterLabel: true
});
export const TextareaField = generateField(renderBlueprintTextarea);
export const EditableTextField = generateField(renderBlueprintEditableText);
export const NumericInputField = generateField(renderBlueprintNumericInput);
export const RadioGroupField = generateField(renderBlueprintRadioGroup);
export const ReactSelectField = generateField(renderReactSelect);
export const SelectField = generateField(renderSelect);
<commit_msg>enable reinitialize on field<commit_after>import sortify from "./sortify"; //tnr TODO: export this from json.sortify when https://github.com/ThomasR/JSON.sortify/issues/11 is resolved
import isNumber from "lodash/isNumber";
import mathExpressionEvaluator from "math-expression-evaluator";
import deepEqual from "deep-equal";
import React from "react";
import { Field } from "redux-form";
import Select from "react-select";
import Uploader from "./Uploader";

import "./style.css";
import {
  InputGroup,
  NumericInput,
  Intent,
  Radio,
  RadioGroup,
  Checkbox,
  EditableText,
  Tooltip,
  Position,
  Switch
} from "@blueprintjs/core";

import { DateInput, DateRangeInput } from "@blueprintjs/datetime";

function getIntent({ showErrorIfUntouched, meta: { touched, error } }) {
  return (touched || showErrorIfUntouched) && error ? Intent.DANGER : "";
}

function getIntentClass({ showErrorIfUntouched, meta: { touched, error } }) {
  return (touched || showErrorIfUntouched) && error ? "pt-intent-danger" : "";
}

function removeUnwantedProps(props) {
  let cleanedProps = { ...props };
  delete cleanedProps.className;
  delete cleanedProps.units;
  delete cleanedProps.showErrorIfUntouched;
  delete cleanedProps.onChange;
  delete cleanedProps.onFieldSubmit;
  delete cleanedProps.onBlur;
  delete cleanedProps.intent;
  delete cleanedProps.intentClass;
  delete cleanedProps.meta;
  delete cleanedProps.defaultValue;
  delete cleanedProps.enableReinitialize;
  delete cleanedProps.tabIndex;
  delete cleanedProps.tooltipError;
  delete cleanedProps.tooltipProps;
  if (cleanedProps.inputClassName) {
    cleanedProps.className = cleanedProps.inputClassName;
    delete cleanedProps.inputClassName;
  }
  return cleanedProps;
}

class AbstractInput extends React.Component {
  componentWillMount() {
    const {
      meta: { dispatch, form },
      defaultValue,
      input: { name, value }
    } = this.props;
    !value &&
      defaultValue !== undefined &&
      dispatch({
        type: "@@redux-form/CHANGE",
        meta: {
          form,
          field: name
        },
        payload: defaultValue
      });
  }

  componentWillReceiveProps({
    meta: { dispatch, form },
    defaultValue,
    input: { name, value }
  }) {
    const { defaultValue: oldDefaultValue, enableReinitialize } = this.props;
    if (
      (!value || enableReinitialize) &&
      !deepEqual(defaultValue, oldDefaultValue)
    ) {
      dispatch({
        type: "@@redux-form/CHANGE",
        meta: {
          form,
          field: name
        },
        payload: defaultValue
      });
    }
  }

  render() {
    const {
      children,
      tooltipProps,
      tooltipError,
      label,
      className,
      showErrorIfUntouched,
      meta,
      noOuterLabel
    } = this.props;
    const { touched, error } = meta;
    const showError = (touched || showErrorIfUntouched) && error;

    const componentToWrap = tooltipError ? (
      <Tooltip
        isDisabled={!showError}
        intent={Intent.DANGER}
        content={error}
        position={Position.TOP}
        {...tooltipProps}
      >
        {children}
      </Tooltip>
    ) : (
      children
    );

    return (

        {label && !noOuterLabel && {label}}
        {componentToWrap}
        {!tooltipError &&
        showError && (

            {error}

        )}

    );
  }
}

export const renderBlueprintDateInput = props => {
  const { input, intent, onFieldSubmit, ...rest } = props;
  return (
    <DateInput
      {...removeUnwantedProps(rest)}
      intent={intent}
      format="MM/DD/YYYY"
      {...input}
      onChange={function(selectedDate) {
        input.onChange(selectedDate);
        onFieldSubmit(selectedDate);
      }}
    />
  );
};

export const renderBlueprintDateRangeInput = props => {
  const { input, intent, onFieldSubmit, ...rest } = props;
  return (
    <DateRangeInput
      {...removeUnwantedProps(rest)}
      intent={intent}
      format="MM/DD/YYYY"
      {...input}
      onChange={function(selectedDate) {
        input.onChange(selectedDate);
        onFieldSubmit(selectedDate);
      }}
    />
  );
};

export const renderBlueprintInput = props => {
  const { input, intent, onFieldSubmit, ...rest } = props;
  return (
    <InputGroup
      {...removeUnwantedProps(rest)}
      intent={intent}
      {...input}
      onKeyDown={function(e) {
        if (e.key === "Enter") {
          onFieldSubmit(e.target.value, { enter: true }, e);
        }
      }}
      onBlur={function(e, val) {
        input.onBlur(e, val);
        onFieldSubmit(e.target ? e.target.value : val, { blur: true }, e);
      }}
    />
  );
};

export const renderBlueprintCheckbox = props => {
  const { input, label, onFieldSubmit, ...rest } = props;
  return (
    <Checkbox
      {...removeUnwantedProps(rest)}
      {...input}
      checked={input.value}
      label={label}
      onChange={function(e, val) {
        input.onChange(e, val);
        onFieldSubmit(e.target ? e.target.value : val);
      }}
    />
  );
};

export const renderBlueprintSwitch = props => {
  const { input, label, onFieldSubmit, ...rest } = props;
  return (
    <Switch
      {...removeUnwantedProps(rest)}
      {...input}
      checked={input.value}
      label={label}
      onChange={function(e, val) {
        input.onChange(e, val);
        onFieldSubmit(e.target ? e.target.value : val);
      }}
    />
  );
};

export const renderFileUpload = props => {
  const { input, onFieldSubmit, ...rest } = props;
  return (
    <Uploader
      fileList={input.value}
      onFieldSubmit={onFieldSubmit}
      {...rest}
      onChange={input.onChange}
    />
  );
};

export const renderBlueprintTextarea = props => {
  const { input, intentClass, inputClassName, onFieldSubmit, ...rest } = props;
  return (
    <textarea
      {...removeUnwantedProps(rest)}
      className={`${intentClass || ""} ${inputClassName ||
        ""} pt-input pt-fill`}
      {...input}
      onBlur={function(e, val) {
        input.onBlur(e, val);
        onFieldSubmit(e.target ? e.target.value : val, { blur: true }, e);
      }}
      onKeyDown={function(e) {
        if (e.keyCode === 13 && (e.metaKey || e.ctrlKey)) {
          onFieldSubmit(e.target.value, { cmdEnter: true }, e);
        }
      }}
    />
  );
};

export const renderBlueprintEditableText = props => {
  const { input, onFieldSubmit, ...rest } = props;
  return (
    <EditableText
      {...removeUnwantedProps(rest)}
      {...input}
      onConfirm={function(value) {
        input.onBlur && input.onBlur(value);
        onFieldSubmit(value);
      }}
    />
  );
};

export const renderReactSelect = props => {
  // spreading input not working, grab the values needed instead
  const {
    async,
    input: { value, onChange },
    hideValue,
    options,
    onFieldSubmit,
    ...rest
  } = props;
  const optsToUse =
    options &&
    options.map(function(opt) {
      if (typeof opt === "string") {
        return { label: opt, value: opt };
      } else if (isNumber(opt)) return { label: opt.toString(), value: opt };
      return opt;
    });
  const valueToUse = //here we're coercing json values into an object with {label,value} because react-select does not seem to recognize the json value directly
    !Array.isArray(value) && typeof value === "object"
      ? optsToUse.find(obj => {
          return deepEqual(obj.value, value);
        })
      : Array.isArray(value)
        ? value.map(val => {
            return optsToUse
              ? optsToUse.find(obj => {
                  return deepEqual(obj.value, val);
                })
              : val;
          })
        : value;

  const propsToUse = {
    ...removeUnwantedProps(rest),
    options: optsToUse,
    value: valueToUse,

    onChange(valOrVals, ...rest) {
      const valToPass = Array.isArray(valOrVals)
        ? valOrVals.map(function(val) {
            return val.value;
          })
        : valOrVals ? valOrVals.value : "";
      onChange(valToPass, ...rest);
      onFieldSubmit(valToPass);
    }
  };
  return async ? <Select.Async {...propsToUse} /> : <Select {...propsToUse} />;
};

export const renderSelect = props => {
  // spreading input not working, grab the values needed instead
  const {
    input: { value, onChange },
    hideValue,
    placeholder,
    onFieldSubmit,
    options,
    ...rest
  } = props;
  return (

      <select
        {...removeUnwantedProps(rest)}
        value={
          placeholder && value === "" ? (
            "__placeholder__"
          ) : typeof value !== "string" ? (
            sortify(value) //deterministically sort and stringify the object/number coming in because select fields only support string values
          ) : (
            value
          )
        }
        {...(hideValue ? { value: "" } : {})}
        onChange={function(e) {
          let val = e.target.value;
          try {
            val = JSON.parse(e.target.value); //try to json parse the string coming in
          } catch (e) {}
          onChange(val);
          onFieldSubmit(val);
        }}
      >
        {placeholder && (
          <option value="__placeholder__" disabled hidden>
            {placeholder}
          </option>
        )}
        {options.map(function(opt, index) {
          let label, value;
          if (typeof opt === "string") {
            //support passing opts like: ['asdf','awfw']
            label = opt;
            value = opt;
          } else if (isNumber(opt)) {
            //support passing opts like: [1,2,3,4]
            label = opt.toString();
            value = opt;
          } else if (Array.isArray(opt)) {
            throw new Error(
              "the option coming in should be an object, not an array!"
            );
          } else {
            //support passing opts the normal way [{label: 'opt1', value: 'hey'}]
            label = opt.label;
            value = opt.value;
          }
          return (
            <option
              key={index}
              value={
                typeof value !== "string" ? (
                  sortify(value) //deterministically sort and stringify the object/number coming in because select fields only support string values
                ) : (
                  value
                )
              }
            >
              {label}
            </option>
          );
        })}
      </select>

  );
};

export const renderBlueprintNumericInput = props => {
  const {
    input,
    hideValue,
    intent,
    inputClassName,
    onFieldSubmit,
    ...rest
  } = props;
  function handleBlurOrButtonClick(stringVal) {
    try {
      const num = mathExpressionEvaluator.eval(stringVal);
      input.onBlur(num);
      onFieldSubmit(num);
    } catch (e) {
      input.onBlur("");
      onFieldSubmit("");
    }
  }
  return (
    <NumericInput
      value={input.value}
      intent={intent}
      {...removeUnwantedProps(rest)}
      {...(hideValue ? { value: "" } : {})}
      className={`pt-fill ${inputClassName || ""}`}
      onValueChange={(numericVal, stringVal) => {
        // needed for redux form to change value
        input.onChange(stringVal);
      }}
      onButtonClick={function(numericVal, stringVal) {
        handleBlurOrButtonClick(stringVal);
      }}
      onBlur={function(e) {
        handleBlurOrButtonClick(e.target.value);
      }}
    />
  );
};

export const renderBlueprintRadioGroup = ({
  input,
  options,
  onFieldSubmit,
  ...rest
}) => {
  return (
    <RadioGroup
      {...input}
      selectedValue={input.value}
      onChange={function(e, val, ...args) {
        input.onChange(e, val, ...args);
        onFieldSubmit(e.target ? e.target.value : val);
      }}
    >
      {options.map(function({ label, value }, index) {
        return (
          <Radio
            {...removeUnwantedProps(rest)}
            key={index}
            value={value}
            label={label}
          />
        );
      })}
    </RadioGroup>
  );
};

function generateField(component, opts) {
  const compWithDefaultVal = withAbstractWrapper(component, opts);
  return function FieldMaker({ name, onFieldSubmit = () => {}, ...rest }) {
    // function onFieldSubmit(e,val) {
    //   _onFieldSubmit && _onFieldSubmit(e.target ? e.target.value : val)
    // }
    return (
      <Field
        onFieldSubmit={onFieldSubmit}
        name={name}
        component={compWithDefaultVal}
        {...rest}
      />
    );
  };
}

export const withAbstractWrapper = (ComponentToWrap, opts = {}) => {
  return props => {
    let defaultProps = {
      ...props,
      intent: getIntent(props),
      intentClass: getIntentClass(props)
    };
    return (
      <AbstractInput {...{ ...opts, ...props }}>
        <ComponentToWrap {...defaultProps} />
      </AbstractInput>
    );
  };
};

export const InputField = generateField(renderBlueprintInput);
export const FileUploadField = generateField(renderFileUpload);
export const DateInputField = generateField(renderBlueprintDateInput);
export const DateRangeInputField = generateField(renderBlueprintDateRangeInput);
export const CheckboxField = generateField(renderBlueprintCheckbox, {
  noOuterLabel: true
});
export const SwitchField = generateField(renderBlueprintSwitch, {
  noOuterLabel: true
});
export const TextareaField = generateField(renderBlueprintTextarea);
export const EditableTextField = generateField(renderBlueprintEditableText);
export const NumericInputField = generateField(renderBlueprintNumericInput);
export const RadioGroupField = generateField(renderBlueprintRadioGroup);
export const ReactSelectField = generateField(renderReactSelect);
export const SelectField = generateField(renderSelect);
<|endoftext|>