<commit_before>var deckNotes;
var deckFields;
var deckName;
var ankiSeparator = '\x1f';

// Huge props to http://stackoverflow.com/a/9507713/500207
function tabulate(datatable, columns, containerString) {
    var table = d3.select(containerString).append("table"),
        thead = table.append("thead"), tbody = table.append("tbody");

    // append the header row
    thead.append("tr").selectAll("th").data(columns).enter().append("th").text(
        function(column) { return column; });

    // create a row for each object in the data
    var rows = tbody.selectAll("tr").data(datatable).enter().append("tr");

    // create a cell in each row for each column
    var cells = rows.selectAll("td").data(function(row) {
        return columns.map(function(column) {
            return {column : column, value : row[column]};
        });
    }).enter().append("td").html(function(d) { return d.value; });

    return table;
}

function sqlToTable(uInt8ArraySQLdb) {
    var db = new SQL.Database(uInt8ArraySQLdb);

    col = db.exec("SELECT models FROM col");
    var modelsFunction = Function('return ' + col[0].values[0][0]);
    var models = modelsFunction();

    var fnames = [];
    for (key in models) {
        if (models.hasOwnProperty(key)) {
            // This happens once every model: FIXME
            deckName = models[key].name;
            models[key].flds.forEach(
                function(val, idx, arr) { fnames.push(val.name); });
        }
    }
    deckFields = fnames;

    // Visualize!
    d3.select("#anki").append("h1").text(deckName);

    // Notes table
    deckNotes = db.exec("SELECT flds FROM notes");

    // Actual notes
    var notes = [];
    var arrayToObj = function(facts) {
        var myObj = {};
        for (var i = 0; i < facts.length; i++) {
            myObj[deckFields[i]] = facts[i];
        }
        return myObj;
    };
    deckNotes[0].values.forEach(
        function(val) { notes.push(arrayToObj(val[0].split(ankiSeparator))); });
    deckNotes = notes;

    // Visualize!
    if (0 == runPreHandlers()) {
        tabulate(deckNotes, deckFields, "#anki");
    }

    // core5000Modify(deckName, deckNotes, deckFields);
}

function ankiBinaryToTable(ankiArray) {
    var compressed = new Uint8Array(ankiArray);
    var unzip = new Zlib.Unzip(compressed);
    var filenames = unzip.getFilenames();
    if (filenames.indexOf("collection.anki2") >= 0) {
        var plain = unzip.decompress("collection.anki2");
        sqlToTable(plain);
    }
}

function ankiURLToTable(ankiURL) {
    var zipxhr = new XMLHttpRequest();
    zipxhr.open('GET', ankiURL, true);
    zipxhr.responseType = 'arraybuffer';
    zipxhr.onload = function(e) { ankiBinaryToTable(this.response); };
    zipxhr.send();
}

$(document).ready(function() {
    var eventHandleToTable = function(event) {
        event.stopPropagation();
        event.preventDefault();
        var f = event.target.files[0];
        if (!f) {
            f = event.dataTransfer.files[0];
        }
        // console.log(f.name);

        var reader = new FileReader();
        reader.onload = function(e) { ankiBinaryToTable(e.target.result); };
        /* // If the callback doesn't need the File object, just use the above.
        reader.onload = (function(theFile) {
            return function(e) {
                console.log(theFile.name);
                ankiBinaryToTable(e.target.result);
            };
        })(f);
        */
        reader.readAsArrayBuffer(f);
    };

    $("#ankiFile").change(eventHandleToTable);

    ankiURLToTable('/n.apkg');
});

function core5000Modify(deckNotes, deckFields) {
    var kanaRegexp = XRegExp('\\[([\\p{Hiragana}\\p{Katakana}]+)\\]', 'g');

    var abbreviations =
        "adn.,adv.,aux.,conj.,cp.,i-adj.,interj.,n.,na-adj.,num.,p.,p. \
case,p. conj.,p. disc.,pron.,v.".split(',');
    var abbreviationsOr = abbreviations.join("|").replace(/\./g, '\\.');

    var kanaKanjiWordRegexp = '([^a-z]+)';
    var romajiRegexp = '([a-z\\s,\\-()’]+)';
    var partOfSpeechRegexp = '((?: |,|' + abbreviationsOr + ')+)';

    var bar = function(s) {
        var arr = s.split(XRegExp('(' + abbreviationsOr + ')'));

        var isAbbreviation = arr.map(
            function(x) { return abbreviations.indexOf(x) >= 0 ? 1 : 0; });
        var isWhitePunctuation =
            arr.map(function(x) { return x.match(/^[\s,]*$/) ? 1 : 0; });
        var isAbbrOrWhitePunct = isAbbreviation.map(
            function(x, i) { return x + isWhitePunctuation[i]; });

        var tmp = removeJunk(isAbbrOrWhitePunct, arr);
        arr = tmp.other_array;
        isAbbrOrWhitePunct = tmp.this_array;

        var pos = [];
        var translation = [];
        arr.map(function(x, i) {
            if (isAbbrOrWhitePunct[i]) {
                pos.push(x);
                translation.push(arr[i + 1]);
            }
        });

        var kanaKanjiMatch =
            s.match(XRegExp(kanaKanjiWordRegexp + ' ' + romajiRegexp + ' ' +
                            partOfSpeechRegexp));
        return {
            pos : pos,
            translation : translation,
            word : kanaKanjiMatch[1],
            romaji : kanaKanjiMatch[2]
        };
    };

    function removeJunk(this_array, other_array) {
        var i = 1;
        while (i < this_array.length) {
            if (this_array[i] == this_array[i - 1] && this_array[i] > 0) {
                this_array.splice(i - 1, 2, 1);
                other_array.splice(i - 1, 2,
                                   other_array[i - 1] + other_array[i]);
            } else {
                i++;
            }
        }
        return {other_array : other_array, this_array : this_array};
    }

    function decodeHtml(html) {
        var txt = document.createElement("textarea");
        txt.innerHTML = html;
        return txt.value;
    }

    var wordColumnReplace = function(s) {
        if (s.search("&") >= 0) {
            s = decodeHtml(s);
        }
        var arr = s.match(
            XRegExp('([^a-z]+)([^\\p{Han}\\p{Katakana}\\p{Hiragana}]+)', 'g'));

        return arr.map(function(s) {
            var decomp = bar(s);
            var posTrans = decomp.pos.map(function(pos, i) {
                return '' + pos +
                       ' ' +
                       decomp.translation[i] + '';
            }).join(" ");
            return '' + decomp.word +
                   ' ' +
                   decomp.romaji + " " + posTrans + ''
        }).join("");
    };

    deckNotes.map(function(note, loc, arr) {
        // Replace [kana] with spans
        note.Reading = note.Reading.replace(kanaRegexp,
                                            function(match, kana, offset, str) {
            return '' + kana + '';
        });

        // Break up Word column into its four separate components
        note.Word = wordColumnReplace(note.Word);

        return note;
    });

    d3.select("body").append("div").attr("id", "core5000");
    tabulate(deckNotes, deckFields, "#core5000");

    return deckNotes;
}

function runPreHandlers() {
    if (0 == "Nayr's Japanese Core5000".localeCompare(deckName)) {
        core5000Modify(deckNotes, deckFields);
        return 1;
    }
    return 0;
}<commit_msg>Updating documentation<commit_after>var deckNotes;
var deckFields;
var deckName;
var ankiSeparator = '\x1f';

// Huge props to http://stackoverflow.com/a/9507713/500207
function tabulate(datatable, columns, containerString) {
    var table = d3.select(containerString).append("table"),
        thead = table.append("thead"), tbody = table.append("tbody");

    // append the header row
    thead.append("tr").selectAll("th").data(columns).enter().append("th").text(
        function(column) { return column; });

    // create a row for each object in the data
    var rows = tbody.selectAll("tr").data(datatable).enter().append("tr");

    // create a cell in each row for each column
    var cells = rows.selectAll("td").data(function(row) {
        return columns.map(function(column) {
            return {column : column, value : row[column]};
        });
    }).enter().append("td").html(function(d) { return d.value; });

    return table;
}

function sqlToTable(uInt8ArraySQLdb) {
    var db = new SQL.Database(uInt8ArraySQLdb);

    col = db.exec("SELECT models FROM col");
    var modelsFunction = Function('return ' + col[0].values[0][0]);
    var models = modelsFunction();

    var fnames = [];
    for (key in models) {
        if (models.hasOwnProperty(key)) {
            // This happens once every model: FIXME
            deckName = models[key].name;
            models[key].flds.forEach(
                function(val, idx, arr) { fnames.push(val.name); });
        }
    }
    deckFields = fnames;

    // Visualize!
    d3.select("#anki").append("h1").text(deckName);

    // Notes table
    deckNotes = db.exec("SELECT flds FROM notes");

    // Actual notes
    var notes = [];
    var arrayToObj = function(facts) {
        var myObj = {};
        for (var i = 0; i < facts.length; i++) {
            myObj[deckFields[i]] = facts[i];
        }
        return myObj;
    };
    deckNotes[0].values.forEach(
        function(val) { notes.push(arrayToObj(val[0].split(ankiSeparator))); });
    deckNotes = notes;

    // Visualize!
    if (0 == runPreHandlers()) {
        tabulate(deckNotes, deckFields, "#anki");
    }

    // core5000Modify(deckName, deckNotes, deckFields);
}

function ankiBinaryToTable(ankiArray) {
    var compressed = new Uint8Array(ankiArray);
    var unzip = new Zlib.Unzip(compressed);
    var filenames = unzip.getFilenames();
    if (filenames.indexOf("collection.anki2") >= 0) {
        var plain = unzip.decompress("collection.anki2");
        sqlToTable(plain);
    }
}

function ankiURLToTable(ankiURL) {
    var zipxhr = new XMLHttpRequest();
    zipxhr.open('GET', ankiURL, true);
    zipxhr.responseType = 'arraybuffer';
    zipxhr.onload = function(e) { ankiBinaryToTable(this.response); };
    zipxhr.send();
}

$(document).ready(function() {
    var eventHandleToTable = function(event) {
        event.stopPropagation();
        event.preventDefault();
        var f = event.target.files[0];
        if (!f) {
            f = event.dataTransfer.files[0];
        }
        // console.log(f.name);

        var reader = new FileReader();
        reader.onload = function(e) { ankiBinaryToTable(e.target.result); };
        /* // If the callback doesn't need the File object, just use the above.
        reader.onload = (function(theFile) {
            return function(e) {
                console.log(theFile.name);
                ankiBinaryToTable(e.target.result);
            };
        })(f);
        */
        reader.readAsArrayBuffer(f);
    };

    $("#ankiFile").change(eventHandleToTable);

    // ankiURLToTable('/n.apkg');
});

/**
* Hook that modifies Nayr's Japanese Core5000 Anki deck
* (see https://ankiweb.net/shared/info/631662071)
*
* @param {Array} deckNotes - array of Anki Notes from the above deck
* @param {String[]} deckFields - names of the fields of the Notes
* @return {Array} an updated version of deckNotes
*
* Each Note object containing properties Expression, Meaning, Reading, English
* Translation, Word, Frequency Order, and Sound.
*
* Kana in the "Reading" field will be changed from "[kana]" to being wrapped in
* tags. And each of the items in the "Word" field, which contains the
*Japanese word, its reading in roumaji (Latin characters), one or more
*parts-of-speech, and English translations, will be encased in  tags
*(ideally these would be their own independent fields, but some rows have more
*than one part-of-speech).
*/
function core5000Modify(deckNotes, deckFields) {
    //------------------------------------------------------------
    // Variables and functions to help deal with the "Word" column
    //------------------------------------------------------------
    // Parts of speech abbreviations
    var abbreviations =
        "adn.,adv.,aux.,conj.,cp.,i-adj.,interj.,n.,na-adj.,num.,p.,p. \
case,p. conj.,p. disc.,pron.,v.".split(',');
    var abbreviationsOr = abbreviations.join("|").replace(/\./g, '\\.');

    // The basic structure of the "Word" column is:
    //
    // 1. some kanji or kana, plus other random things like commas, parentheses,
    // both ascii and full-width.
    // 2. Some roumaji
    // 3. One or more parts of speech, using the above abbreviations
    // 4. English translations.
    //
    // The following three strings will be the regexps that match #1--#3.
    // They've been carefully chosen to work with wrinkles in the database,
    // e.g., more than one of the above four-step sequences in a single row,
    // multiple adjacent parts-of-speech, or multiple
    // part-of-speech-and-translation pairs.
    var kanaKanjiWordRegexp = '([^a-z]+)';
    var romajiRegexp = '([a-z\\s,\\-()’]+)';
    var partOfSpeechRegexp = '((?: |,|' + abbreviationsOr + ')+)';

    // This string's regexp is used to separate multiple sequences of #1--#4
    // above. All these strings intended to become regexps will go through
    // XRegExp, which expands out the Han/Katakana/Hiragana groups.
    var completeWordRegexp =
        '([^a-z]+)([^\\p{Han}\\p{Katakana}\\p{Hiragana}]+)';

    // Break up a string containing one {kanji/kana + roumaji + part-of-speech +
    // translations} sequence. The critical idea in this function is to split
    // the input string between part-of-speech-abbreviations, and do some
    // processing on that to handle two edge cases:
    //
    // 1. "いろいろ iroiro adv., na-adj. various" <-- more than one adjacent
    //     part-of-speech abbreviation separated by a comma
    // 2. "余り amari adv. the rest n. (not) much" <-- more than one
    //     part-of-speech/translation pairs.
    //
    // It handles both these cases by splitting the string into an array along
    // (and including) part-of-speech-abbreviation boundaries. To handle edge
    // case 1 above, it finds elements of the resulting array that are
    // between part-of-speech abbreviations but which are
    // whitespace/punctuation, and merges those elements into a single
    // "part-of-speech" element.
    //
    // Then it builds an array of parts-of-speech and a matching array of
    // translations. This handles case 2 above. These two arrays, as well as the
    // kanji/kana and roumaji, are returned as an object.
    function bar(seqString) {
        var arr = seqString.split(XRegExp('(' + abbreviationsOr + ')'));

        var isAbbreviation = arr.map(
            function(x) { return abbreviations.indexOf(x) >= 0 ? 1 : 0; });
        var isWhitePunctuation =
            arr.map(function(x) { return x.match(/^[\s,]*$/) ? 1 : 0; });
        var isAbbrOrWhitePunct = isAbbreviation.map(
            function(x, i) { return x + isWhitePunctuation[i]; });

        // combineJunk will find [..., "adv.", ",", "na-adj.", ...] and splice
        // it into [..., "adv., na-adj.", ...].
        var tmp = combineJunk(isAbbrOrWhitePunct, arr);
        arr = tmp.data_array;
        isAbbrOrWhitePunct = tmp.indicator_array;
        // Updated arr and isAbbrOrWhitePunct. We need the latter to build the
        // return object.

        // Part-of-speech array and translation array, which will go itno the
        // return object. We rely on each part-of-speech element in arr to be
        // followed by a translation. So far, this happens.
        var pos = [];
        var translation = [];
        arr.map(function(x, i) {
            if (isAbbrOrWhitePunct[i]) {
                pos.push(x);
                translation.push(arr[i + 1]);
            }
        });

        // Grab the initial kanji/kana as well as the roumaji. String.match()
        // will return a three-element array here: the total match, and the two
        // groups corresponding to the two regexps.
        var kanaKanjiMatch =
            seqString.match(XRegExp(kanaKanjiWordRegexp + ' ' + romajiRegexp +
                                    ' ' + partOfSpeechRegexp));
        return {
            pos : pos,
            translation : translation,
            word : kanaKanjiMatch[1],
            romaji : kanaKanjiMatch[2]
        };
    };

    function combineJunk(indicator_array, data_array) {
        var i = 1;
        while (i < indicator_array.length) {
            if (indicator_array[i] == indicator_array[i - 1] && indicator_array[i] > 0) {
                indicator_array.splice(i - 1, 2, 1);
                data_array.splice(i - 1, 2,
                                   data_array[i - 1] + data_array[i]);
            } else {
                i++;
            }
        }
        return {data_array : data_array, indicator_array : indicator_array};
    }

    function decodeHtml(html) {
        var txt = document.createElement("textarea");
        txt.innerHTML = html;
        return txt.value;
    }

    var wordColumnReplace = function(s) {
        if (s.search("&") >= 0) {
            s = decodeHtml(s);
        }
        var arr = s.match(XRegExp(completeWordRegexp, 'g'));

        return arr.map(function(s) {
            var decomp = bar(s);
            var posTrans = decomp.pos.map(function(pos, i) {
                return '' + pos +
                       ' ' +
                       decomp.translation[i] + '';
            }).join(" ");
            return '' + decomp.word +
                   ' ' +
                   decomp.romaji + " " + posTrans + ''
        }).join("");
    };

    //--------------------------------------------
    // Variable for Reading column cleanup of kana
    //--------------------------------------------
    var kanaRegexp = XRegExp('\\[([\\p{Hiragana}\\p{Katakana}]+)\\]', 'g');

    //-----------------
    // Complete cleanup
    //-----------------
    deckNotes.map(function(note, loc, arr) {
        // Break up Word column into its four separate components
        note.Word = wordColumnReplace(note.Word);

        // Replace [kana] with spans
        note.Reading = note.Reading.replace(kanaRegexp,
                                            function(match, kana, offset, str) {
            return '' + kana + '';
        });

        return note;
    });

    //-------------------------
    // Visualization and return
    //-------------------------
    d3.select("body").append("div").attr("id", "core5000");
    tabulate(deckNotes, deckFields, "#core5000");

    return deckNotes;
}

function runPreHandlers() {
    if (0 == "Nayr's Japanese Core5000".localeCompare(deckName)) {
        core5000Modify(deckNotes, deckFields);
        return 1;
    }
    return 0;
}<|endoftext|>


<commit_before>var WebKit = require('../');
var expect = require('expect.js');
var fs = require('fs');

describe("unload method", function suite() {
	this.timeout(10000);
	it("should be set immediately to an empty document with an empty url", function(done) {
		var view = new WebKit();
		var uri = 'http://localhost';
		view.load(uri).once('load', function() {
			view.unload(function(err) {
				expect(view.uri).to.be("");
				expect(view.looping).to.be(0);
				view.run("document.documentElement.outerHTML;", function(err, html) {
					expect(err).to.not.be.ok();
					expect(html).to.be('');
					done();
				});
			});
		});
	});
	it("should allow to load another uri just after", function(done) {
		var view = new WebKit();
		var uri = 'http://google.com';
		view.load(uri).once('load', function() {
			console.log("first load");
			view.unload(function(err) {
				view.load('http://google.com', function(err) {
					expect(err).to.not.be.ok();
					console.log("second load cb");
				}).on('ready', function() {
					console.log("second ready event");
				})
				.on('load', function() {

					this.html(function(err, html) {
						console.log(html.length);
						done();
					});
				});
			});
		});
	});
});
<commit_msg>Clean unload test<commit_after>var WebKit = require('../');
var expect = require('expect.js');
var fs = require('fs');

describe("unload method", function suite() {
	this.timeout(10000);
	it("should be set immediately to an empty document with an empty url", function(done) {
		var view = new WebKit();
		var uri = 'http://localhost';
		view.load(uri).once('load', function() {
			view.unload(function(err) {
				expect(view.uri).to.be("");
				expect(view.looping).to.be(0);
				view.run("document.documentElement.outerHTML;", function(err, html) {
					expect(err).to.not.be.ok();
					expect(html).to.be('');
					done();
				});
			});
		});
	});
	it("should allow to load another uri just after", function(done) {
		var view = new WebKit();
		var uri = 'http://google.com';
		view.load(uri).once('load', function() {
			view.unload(function(err) {
				view.load('http://google.com', function(err) {
					expect(err).to.not.be.ok();
				}).html(function(err, html) {
					expect(err).to.not.be.ok();
					expect(html.length).to.be.greaterThan(200);
					done();
				});
			});
		});
	});
});
<|endoftext|>


<commit_before>var request = require('request'),
  _ = require('underscore'),
  gist = require('../../lib/gist'),
  markdown = require('../../lib/markdown'),
  lastGet = new Date(2000,1,1),
  async = require('async'),
  cache;

var Posts = function () {
  this.respondsWith = ['html','atom', 'json'];

  this.feed = function (req, resp, params) {
    getGists(onGistsRetrieved, this);

    function onGistsRetrieved(app, body) {
      var feed = {
        gists: _.chain(body)
          .filter(isBlogGist)
          .map(toViewModel)
          .sortBy(date)
          .value().reverse()
      };

      feed.toXml = function () {

        var lastUpdated = _.chain(this.gists)
          .max(function (entry) { return entry.updated_at; })
          .value();

        var response = '<?xml version="1.0" encoding="utf-8"?>\n' +
          '<feed xmlns="http://www.w3.org/2005/Atom"><title>Withouttheloop.com</title>\n' +
          '<id>http://withouttheloop.com/</id>\n' +
          '<link rel="self" href="http://withouttheloop.com/feed" />\n' +
          '<updated>' + new Date().toJSON() + '</updated>'; // TODO: how to fix this?

        _(this.gists).each(function (gist) {
          response += toEntryNode(gist);
          response += '\n';
        });
        return response + '</feed>';
      };

      app.respond(feed, {
        format: 'xml'
      });

      function toEntryNode(gistEntry) {
        return '\n<entry>\n<title>' + gistEntry.description + '</title>' +
          '<link  href="' + gistEntry.url + '" />\n' +
          '<id>' + gistEntry.url + '</id>\n' +
          '<content type="html"><![CDATA[' + gistEntry.content_html + ']]></content>\n' +
          '<updated>' + gistEntry.updated_at.toJSON() + '</updated>\n' +
          '<author><name>Liam McLennan</name></author>' +
          '</entry>\n';
      }
    }
  };

  this.index = function (req, resp, params) {
    getGists(onGistsRetrieved, this);

    function onGistsRetrieved(app, body) {
      app.respond({
        gists: _.chain(body)
          .filter(isBlogGist)
          .map(toViewModel)
          .sortBy(date)
          .value().reverse()
      });
    }

  };

  function getGists(successCallback, app) {
    var gistListUrl = 'https://api.github.com/users/liammclennan/gists',
      age = (new Date() - lastGet) / 60000;

    console.log(age);
    if (age < 5) {
      successCallback(app, cache);
      return undefined;
    }

    request({ url: gistListUrl, json: true }, function (error, response, body) {
      console.log('get from github');
      if (!error && response.statusCode == 200) {
        cache = body;

        // NOTE: the two arrays must match elements by index, exactly
        var cacheBlogItemArray = _.chain(cache).filter(isBlogGist).toArray().value();
        console.log('cache item array count %s', cacheBlogItemArray.length);
        var asyncTasks = _.chain(body)
          .filter(isBlogGist)
          .map(function (rawGist) { return rawGist.files[_(rawGist.files).keys()[0]].raw_url; })
          .map(function (raw_url) { return async.apply(gist.read, { raw_url: raw_url }); })
          .toArray()
          .value();

        console.log('getting raw markdown for each blog gist');
        async.parallel(asyncTasks, function onGotRawMarkdown(err, rawMarkdownItems) {
          if (err) {
            console.log("LOG: failed to get raw markdown, using cache. error = %j", err);
            return successCallback(app, cache);
          }

          var convertMarkdownAsyncTasks = _.map(rawMarkdownItems, function (rawMarkdown) {
            return async.apply(markdown.convertViaGithub, rawMarkdown);
          });

          // use GitHub to convert the markdown to HTML
          console.log('converting raw markdown to html');
          async.parallel(convertMarkdownAsyncTasks, function (err, htmlItems) {
            if (err) {
              console.log("LOG: failed to convert markdown via github. error = %s", err);
              return successCallback(app, cache);
            }

            // put the html back into the correct object (the cached copy)
            // since async will give us the items in the correct order, we can
            // can use the arrat index.
            _(htmlItems).each(function (content_html, index) {
              cacheBlogItemArray[index].content_html = content_html;
            });

            lastGet = new Date();
            successCallback(app, body);
          });

        });
      } else {
        console.log("LOG: failed to get gists from github. Using cache.");
        successCallback(app, cache);
      }
    });
  }

  function isBlogGist(gist) {
   var fileName = gist.files[_(gist.files).keys()[0]].filename;
    return /blog_.+\.md/.test(fileName);
  }

  function toViewModel(gist) {
    var firstFile = gist.files[_(gist.files).keys()[0]];
    return {
      id: gist.id,
      description: gist.description,
      created_at: new Date(gist.created_at),
      updated_at: new Date(gist.updated_at),
      url: 'https://gist.github.com/' + gist.id,
      commentsSummaryText: gist.comments > 0 ? gist.comments + ' comments' : 'no comments yet',
      content_html: gist.content_html,
      raw_url: firstFile.raw_url
    };
  }

  function date(gist) {
    return gist.created_at;
  }

};

exports.Posts = Posts;

// mock request
// request = function(options, callback) {
//   callback(null, { statusCode: 200 }, {
//     gists: [
//       {
//         repo: 1,
//         description: 'blah title',
//         files: ['blog_blah.md'],
//         created_at: new Date().toString()
//       },
//       {
//         repo: 2,
//         description: 'foo title',
//         files: ['blog_foo.md'],
//         created_at: new Date().toString()
//       }
//     ]
//   })
// };<commit_msg>fixed feed updated element<commit_after>var request = require('request'),
  _ = require('underscore'),
  gist = require('../../lib/gist'),
  markdown = require('../../lib/markdown'),
  lastGet = new Date(2000,1,1),
  async = require('async'),
  cache;

var Posts = function () {
  this.respondsWith = ['html','atom', 'json'];

  this.feed = function (req, resp, params) {
    getGists(onGistsRetrieved, this);

    function onGistsRetrieved(app, body) {
      var feed = {
        gists: _.chain(body)
          .filter(isBlogGist)
          .map(toViewModel)
          .sortBy(date)
          .value().reverse()
      };

      feed.toXml = function () {

        var lastUpdated = _.chain(this.gists)
          .max(function (entry) { return entry.updated_at; })
          .value();

        var response = '<?xml version="1.0" encoding="utf-8"?>\n' +
          '<feed xmlns="http://www.w3.org/2005/Atom"><title>Withouttheloop.com</title>\n' +
          '<id>http://withouttheloop.com/</id>\n' +
          '<link rel="self" href="http://withouttheloop.com/feed" />\n' +
          '<updated>' + lastUpdated.updated_at.toJSON() + '</updated>'; // TODO: how to fix this?

        _(this.gists).each(function (gist) {
          response += toEntryNode(gist);
          response += '\n';
        });
        return response + '</feed>';
      };

      app.respond(feed, {
        format: 'xml'
      });

      function toEntryNode(gistEntry) {
        return '\n<entry>\n<title>' + gistEntry.description + '</title>' +
          '<link  href="' + gistEntry.url + '" />\n' +
          '<id>' + gistEntry.url + '</id>\n' +
          '<content type="html"><![CDATA[' + gistEntry.content_html + ']]></content>\n' +
          '<updated>' + gistEntry.updated_at.toJSON() + '</updated>\n' +
          '<author><name>Liam McLennan</name></author>' +
          '</entry>\n';
      }
    }
  };

  this.index = function (req, resp, params) {
    getGists(onGistsRetrieved, this);

    function onGistsRetrieved(app, body) {
      app.respond({
        gists: _.chain(body)
          .filter(isBlogGist)
          .map(toViewModel)
          .sortBy(date)
          .value().reverse()
      });
    }

  };

  function getGists(successCallback, app) {
    var gistListUrl = 'https://api.github.com/users/liammclennan/gists',
      age = (new Date() - lastGet) / 60000;

    console.log(age);
    if (age < 5) {
      successCallback(app, cache);
      return undefined;
    }

    request({ url: gistListUrl, json: true }, function (error, response, body) {
      console.log('get from github');
      if (!error && response.statusCode == 200) {
        cache = body;

        // NOTE: the two arrays must match elements by index, exactly
        var cacheBlogItemArray = _.chain(cache).filter(isBlogGist).toArray().value();
        console.log('cache item array count %s', cacheBlogItemArray.length);
        var asyncTasks = _.chain(body)
          .filter(isBlogGist)
          .map(function (rawGist) { return rawGist.files[_(rawGist.files).keys()[0]].raw_url; })
          .map(function (raw_url) { return async.apply(gist.read, { raw_url: raw_url }); })
          .toArray()
          .value();

        console.log('getting raw markdown for each blog gist');
        async.parallel(asyncTasks, function onGotRawMarkdown(err, rawMarkdownItems) {
          if (err) {
            console.log("LOG: failed to get raw markdown, using cache. error = %j", err);
            return successCallback(app, cache);
          }

          var convertMarkdownAsyncTasks = _.map(rawMarkdownItems, function (rawMarkdown) {
            return async.apply(markdown.convertViaGithub, rawMarkdown);
          });

          // use GitHub to convert the markdown to HTML
          console.log('converting raw markdown to html');
          async.parallel(convertMarkdownAsyncTasks, function (err, htmlItems) {
            if (err) {
              console.log("LOG: failed to convert markdown via github. error = %s", err);
              return successCallback(app, cache);
            }

            // put the html back into the correct object (the cached copy)
            // since async will give us the items in the correct order, we can
            // can use the arrat index.
            _(htmlItems).each(function (content_html, index) {
              cacheBlogItemArray[index].content_html = content_html;
            });

            lastGet = new Date();
            successCallback(app, body);
          });

        });
      } else {
        console.log("LOG: failed to get gists from github. Using cache.");
        successCallback(app, cache);
      }
    });
  }

  function isBlogGist(gist) {
   var fileName = gist.files[_(gist.files).keys()[0]].filename;
    return /blog_.+\.md/.test(fileName);
  }

  function toViewModel(gist) {
    var firstFile = gist.files[_(gist.files).keys()[0]];
    return {
      id: gist.id,
      description: gist.description,
      created_at: new Date(gist.created_at),
      updated_at: new Date(gist.updated_at),
      url: 'https://gist.github.com/' + gist.id,
      commentsSummaryText: gist.comments > 0 ? gist.comments + ' comments' : 'no comments yet',
      content_html: gist.content_html,
      raw_url: firstFile.raw_url
    };
  }

  function date(gist) {
    return gist.created_at;
  }

};

exports.Posts = Posts;

// mock request
// request = function(options, callback) {
//   callback(null, { statusCode: 200 }, {
//     gists: [
//       {
//         repo: 1,
//         description: 'blah title',
//         files: ['blog_blah.md'],
//         created_at: new Date().toString()
//       },
//       {
//         repo: 2,
//         description: 'foo title',
//         files: ['blog_foo.md'],
//         created_at: new Date().toString()
//       }
//     ]
//   })
// };<|endoftext|>


<commit_before>var assert = require('assert'),
  fs = require('fs'),
  request = require('supertest'),
  express = require('express');

var danzi = require('..');

var uploadPath = __dirname + '/upload';

var app = express();

app
  .use(express.bodyParser())
  .use(danzi({ path: uploadPath }))
  .use(function(req, res) {
    if (req.files && req.files.hasOwnProperty('file')) {
      res.send(req.files.file.uri);
    }
    else {
      res.json(req.body);
    }
  });

describe('post request test', function() {
  it('should response to request param', function(done) {
    var param = { name: "test" };
    request(app)
      .post('/')
      .send(param)
      .expect('Content-Type', /json/)
      .expect(200)
      .expect(param, done);
  });

  it('should parse x-www-form-urlencoded', function(done){
    request(app)
      .post('/')
      .set('Content-Type', 'application/x-www-form-urlencoded')
      .send('user=alice')
      .expect({user: "alice"}, done);
  });

  describe('with multipart/form-data', function() {
    it('should populate req.body', function(done) {
      var req = request(app);
      req
        .post('/')
        .field('user', 'Alice')
        .expect({user: "Alice"}, done);
    });
  });
});

describe('upload a file', function() {
  it('should has uploaded file', function(done) {
    request(app)
      .post('/')
      .attach('file', __dirname + '/fixture.txt')
      .expect(200)
      .end(function(err, res) {
        fs.exists(res.text, function(exists) {
          assert.equal(exists, true);
          done();
        });
      });
  });

  after(function(done) {
    var files = fs.readdirSync(uploadPath);
    for(var key in files) {
      fs.unlinkSync(uploadPath + '/' + files[key]);
    }
    fs.rmdirSync(uploadPath);
    done();
  });

});
<commit_msg>Refactor the test<commit_after>var assert = require('assert'),
  fs = require('fs'),
  request = require('supertest'),
  express = require('express');

var danzi = require('..');

var uploadPath = __dirname + '/upload';

describe('post request test', function() {
  var app = express();

  app
    .use(express.bodyParser())
    .use(danzi({ path: uploadPath }));

  app.post('/', function(req, res) {
    if (req.files && req.files.hasOwnProperty('file')) {
      res.send(req.files.file.uri);
    }
    else {
      res.json(req.body);
    }
  });

  it('should response to request param', function(done) {
    var param = { name: "test" };
    request(app)
      .post('/')
      .send(param)
      .expect('Content-Type', /json/)
      .expect(200)
      .expect(param, done);
  });

  it('should parse x-www-form-urlencoded', function(done){
    request(app)
      .post('/')
      .set('Content-Type', 'application/x-www-form-urlencoded')
      .send('user=alice')
      .expect({user: "alice"}, done);
  });

  describe('with multipart/form-data', function() {
    it('should populate req.body', function(done) {
      var req = request(app);
      req
        .post('/')
        .field('user', 'Alice')
        .expect({user: "Alice"}, done);
    });
  });

  describe('upload a file', function() {
    it('should have a uploaded file', function(done) {
      request(app)
        .post('/')
        .attach('file', __dirname + '/fixture.txt')
        .expect(200)
        .end(function(err, res) {
          fs.exists(res.text, function(exists) {
            assert.equal(exists, true);
            done();
          });
        });
    });
  });
});

after(function(done) {
  var files = fs.readdirSync(uploadPath);
  for(var key in files) {
    fs.unlinkSync(uploadPath + '/' + files[key]);
  }
  fs.rmdirSync(uploadPath);
  done();
});
<|endoftext|>


<commit_before><commit_msg>Update anti.js<commit_after><|endoftext|>


<commit_before>var assert = require('assert'),
	crypto = require('crypto'),
	utils = require('./utils'), //this module is not publicly available
	request = require('request')
	xml2js = require('xml2js'),
	CheckOut = require('./check-out'),
	Polling = require('./polling'),
	OrderProcessing = require('./order-processing'),
	OrderReporting = require('./order-reporting')

function GoogleCheckout(settings) {
	var self = this;

	assert.ok(settings.merchantNumber, 'settings.merchantNumber is required');
	assert.ok(settings.merchantKey, 'settings.merchantKey is required');
	assert.ok(settings.currency, 'settings.currency is required');

	self.settings = settings;

	self.CheckOut = new CheckOut(self);
	self.Polling = new Polling(self);
	self.OrderProcessing = new OrderProcessing(self);
}

GoogleCheckout.ImageUrl = 'https://checkout.google.com/buttons/checkout.gif?merchant_id={merchantNumber}&w=180&h=46&style=trans&variant={variant}&loc=en_US';

GoogleCheckout.prototype.postXML = function (url, xml, callback) {
	var self = this
		, options = {
			url : url.replace(/\{merchantNumber\}/gi, self.settings.merchantNumber)
					 .replace(/\{merchantKey\}/gi, self.settings.merchantKey)
			, method : 'POST'
			, body : xml
		};

	request(options, function (error, response, body) {
		if (error) {
			return callback(error, null);
		}
		else if (body) {
			var parser = new xml2js.Parser();

			parser.addListener('end', function (result) {
				return callback(null, camelCaseObjectKeys(result));
			});

			parser.parseString(body);
		}
	});
};

GoogleCheckout.prototype.getButtonUrl = GoogleCheckout.getImageUrl = function (variant, merchantNumber) {
	var self = this;

	//Since this function is also static method, we need to check to see
	//what the constructor of `this` is to see where we should get the
	//merchant number from
	if (self.constructor.name == 'GoogleCheckout') {
		merchantNumber = merchantNumber || self.settings.merchantNumber
	}

	switch (variant) {
		case 'disabled':
			break;
		case 'text':
			break;
		default:
			variant = 'text';
	}

	return GoogleCheckout.ImageUrl
			.replace('{merchantNumber}', merchantNumber)
			.replace('{variant}', variant);
};

//constructor should accept merchant number and merchant key
module.exports = function (globalSettings) {
	assert.ok(globalSettings.merchantNumber, 'settings.merchantNumber is required');
	assert.ok(globalSettings.merchantKey, 'settings.merchantKey is required');
	assert.ok(globalSettings.currency, 'settings.currency is required');

	var GoogleCheckoutShortcuts = {
		getClient : getGoogleCheckoutClient,
		getButtonUrl : getGoogleCheckoutImageUrl
	};

	return function (request, response, next) {
		request.GoogleCheckout = GoogleCheckoutShortcuts;
	};

	function getGoogleCheckoutImageUrl (variant, merchantNumber) {
		return GoogleCheckout.getButtonUrl(variant, merchantNumber || globalSettings.merchantNumber);
	}

	function getGoogleCheckoutClient (localSettings) {
		var gc = new GoogleCheckout(localSettings || globalSettings)
		return gc;
	}
};

module.exports.GoogleCheckout = GoogleCheckout;

/*
 * Return a new object where all keys like:
 * 		this-thing-here
 * become:
 * 		thisThingHere
 */

function camelCaseObjectKeys(obj) {
	var newObj = (Array.isArray(obj))
		? new Array(obj.length)
		: {};

	utils.map(obj, function (key, value) {
		var newKey;

		if (typeof(key) === 'string') {
			newKey = key.replace(/-([a-z]{1})/gi, function (_, letter) { return letter.toUpperCase() })
		}
		else {
			newKey = key;
		}

		if (typeof(value) === 'object') {
			newObj[newKey] = camelCaseObjectKeys(value);
		}
		else {
			newObj[newKey] = value;
		}
	});

	if (!Object.keys(newObj).length) {
		newObj = null;
	}

	return newObj;
}<commit_msg>add error event handler on the xml parser<commit_after>var assert = require('assert'),
	crypto = require('crypto'),
	utils = require('./utils'), //this module is not publicly available
	request = require('request')
	xml2js = require('xml2js'),
	CheckOut = require('./check-out'),
	Polling = require('./polling'),
	OrderProcessing = require('./order-processing'),
	OrderReporting = require('./order-reporting');

function GoogleCheckout(settings) {
	var self = this;

	assert.ok(settings.merchantNumber, 'settings.merchantNumber is required');
	assert.ok(settings.merchantKey, 'settings.merchantKey is required');
	assert.ok(settings.currency, 'settings.currency is required');

	self.settings = settings;

	self.CheckOut = new CheckOut(self);
	self.Polling = new Polling(self);
	self.OrderProcessing = new OrderProcessing(self);
	self.OrderReporting = new OrderReporting(self);
}

GoogleCheckout.ImageUrl = 'https://checkout.google.com/buttons/checkout.gif?merchant_id={merchantNumber}&w=180&h=46&style=trans&variant={variant}&loc=en_US';

GoogleCheckout.prototype.postXML = function (url, xml, callback) {
	var self = this
		, options = {
			url : url.replace(/\{merchantNumber\}/gi, self.settings.merchantNumber)
					 .replace(/\{merchantKey\}/gi, self.settings.merchantKey)
			, method : 'POST'
			, body : xml
		};

	request(options, function (error, response, body) {
		if (error) {
			return callback(error, null);
		}
		else if (body) {
			var parser = new xml2js.Parser();

			parser.on('end', function (result) {
				return callback(null, camelCaseObjectKeys(result));
			});

			parser.on('error', function (error) {
				return callback(error, body);
			});

			parser.parseString(body);
		}
	});
};

GoogleCheckout.prototype.getButtonUrl = GoogleCheckout.getImageUrl = function (variant, merchantNumber) {
	var self = this;

	//Since this function is also static method, we need to check to see
	//what the constructor of `this` is to see where we should get the
	//merchant number from
	if (self.constructor.name == 'GoogleCheckout') {
		merchantNumber = merchantNumber || self.settings.merchantNumber
	}

	switch (variant) {
		case 'disabled':
			break;
		case 'text':
			break;
		default:
			variant = 'text';
	}

	return GoogleCheckout.ImageUrl
			.replace('{merchantNumber}', merchantNumber)
			.replace('{variant}', variant);
};

//constructor should accept merchant number and merchant key
module.exports = function (globalSettings) {
	assert.ok(globalSettings.merchantNumber, 'settings.merchantNumber is required');
	assert.ok(globalSettings.merchantKey, 'settings.merchantKey is required');
	assert.ok(globalSettings.currency, 'settings.currency is required');

	var GoogleCheckoutShortcuts = {
		getClient : getGoogleCheckoutClient,
		getButtonUrl : getGoogleCheckoutImageUrl
	};

	return function (request, response, next) {
		request.GoogleCheckout = GoogleCheckoutShortcuts;
	};

	function getGoogleCheckoutImageUrl (variant, merchantNumber) {
		return GoogleCheckout.getButtonUrl(variant, merchantNumber || globalSettings.merchantNumber);
	}

	function getGoogleCheckoutClient (localSettings) {
		var gc = new GoogleCheckout(localSettings || globalSettings)
		return gc;
	}
};

module.exports.GoogleCheckout = GoogleCheckout;

/*
 * Return a new object where all keys like:
 * 		this-thing-here
 * become:
 * 		thisThingHere
 */

function camelCaseObjectKeys(obj) {
	var newObj = (Array.isArray(obj))
		? new Array(obj.length)
		: {};

	utils.map(obj, function (key, value) {
		var newKey;

		if (typeof(key) === 'string') {
			newKey = key.replace(/-([a-z]{1})/gi, function (_, letter) { return letter.toUpperCase() })
		}
		else {
			newKey = key;
		}

		if (typeof(value) === 'object') {
			newObj[newKey] = camelCaseObjectKeys(value);
		}
		else {
			newObj[newKey] = value;
		}
	});

	if (!Object.keys(newObj).length) {
		newObj = null;
	}

	return newObj;
}<|endoftext|>


<commit_before>/*
    7Breaths
    An application to simplify the clinical measurement of a person's respiratory rate
    Copyright (C) 2013  Neville Dastur neville [at] clinsoftsolutions.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
    PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
    FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

var APP = Alloy.Globals.APP;

if(OS_ANDROID){
    Alloy = require("alloy")
    _ = require("alloy/underscore")._
}

$.DEFAULT_ROLE_TEXT = "Please choose one ...";

var dataStore = require('datastore');

var ARGS = arguments[0] || {};
$.reachedBottom = false;
$.scrollBottomY = 0;

$.init = function() {
    var htmlfile = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, "/tandc.html");
    var html = htmlfile.read().text;
    $.styledlabel.html = html;

    $.roleLabel.text = $.DEFAULT_ROLE_TEXT;

    $.reg_info.text = "Registration is entirely optional, but allows us to better"
    + " understand the data collected and also allows us send feedback to you.";

    Ti.App.addEventListener("androidback" , function() {
        // TODO don't allow close unless ok or cancel selected, i.e. prevent normal back button behaviour
        //this.close();
    });

    $.styledlabel.addEventListener("postlayout",function(e){
        $.scrollBottomY = e.source.getRect().height - $.ScrollWrapper.getSize().height;
        Ti.API.debug("Set $.scrollBottomY = " + $.scrollBottomY);
    });

    $.ScrollWrapper.addEventListener("scroll",$.scrollWrapper_ScrollEvent);

    $.accept_but.addEventListener("click",function(e){
        if ($.reachedBottom === false) {
            Ti.Analytics.featureEvent('APP:Tried_TandC_Accepted');
            alert("Please scroll down through all the Terms and Conditions before accepting them. Thank you.")
            return;
        }
        Ti.Analytics.featureEvent("APP:TandC_ACCEPTED");
        Ti.App.Properties.setBool("APP:TandC_ACCEPTED", true);
        $.scrollableView.setCurrentPage(1);
    });

    $.reject_but.addEventListener("click",function(e){
        Ti.Analytics.featureEvent('APP:TandC_Rejected');
        alert("Thank you for your interest in 7Breaths. As the terms are not acceptable please un-install the application.")
    });

    $.rolePickerWrapper.addEventListener("click",function(e){
        Ti.API.debug("rolePickerWrapper click")
        $.rolePickerWrapper.visible = false;
    });

    $.rolePicker.addEventListener("click", function(e){
        $.reg_firstname.blur();
        $.reg_surname.blur();
        $.reg_email.blur();
        $.rolePickerWrapper.visible = true;
    });

    $.rolePickerControl.addEventListener("change",function(e){
        Ti.API.debug("Click on picker row: " + e.row.title);
    });

    $.select_role_but.addEventListener("click",function(e){
        Ti.API.debug("Picker row selected: " + $.rolePickerControl.getSelectedRow(0).title);
        $.roleLabel.text = $.rolePickerControl.getSelectedRow(0).title;
    });

    $.register_but.addEventListener("click",function(e){
        var validate_msg = $.Validates();
        if(0 === validate_msg.length) {
            dataStore.RegisterUser(reg_email.value, reg_firstname.value, reg_surname.value,
                $.roleLabel.text);
            $.Window.close();
        }
        else {
            alert(validate_msg);
        }
    });

    $.skip_but.addEventListener("click",function(e){
        var _skipCount = Ti.App.Properties.getInt("APP:REG_SKIP_COUNT", 0) + 1;
        Ti.App.Properties.setInt("APP:REG_SKIP_COUNT", _skipCount);
        if (_skipCount < 3) {
            // We only prompt the user twice for registration if skipped
            // and with increasing intervals
            Ti.App.Properties.setInt("APP:REG_COUNTDOWN", _skipCount * 2);
        }
        $.Window.close();
    });

    // If T&C already accepted then go straight to registration page
    if (Ti.App.Properties.getBool("APP:TandC_ACCEPTED", false)) {
        $.scrollableView.setCurrentPage(1);
    }

}

/**
 * Validate the fields
 * If fails then returns a message. So emmpty string indicates success
 */
$.Validates = function() {
    var msg = "";
    if ( $.reg_email.value.length < 5, $.reg_firstname.value.length < 2, $.reg_surname.value.length < 2) {
        msg += "All fields require a value please.\n";

        if ( $.reg_email.value.length < 5) {
            $.reg_email.borderColor = "#f00";
        }
        if ( $.reg_firstname.value.length < 5) {
            $.reg_firstname.borderColor = "#f00";
        }
        if ( $.reg_surname.value.length < 5) {
            $.reg_surname.borderColor = "#f00";
        }
    }

    if ($.roleLabel.text === $.DEFAULT_ROLE_TEXT) {
        msg += "Please select a role.\n";
    }

    var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;

    if($.reg_email.value.length >= 5 && reg.test($.reg_email.value) == false) {
        msg += "The email address appears to be invalid. Please correct";
        $.reg_email.borderColor = "#f00";
    }

    return msg;
}

$.scrollWrapper_ScrollEvent = function(_event) {
    //Ti.API.info("Scroll x="+_event.x+" y="+_event.y);
    if( $.isScrollBottom(_event.y) ) {
        Ti.API.info("ScrollView reached the bottom.");
        $.reachedBottom = true;
        // Don't need to listen any more
        $.ScrollWrapper.removeEventListener("scroll",$.scrollWrapper_ScrollEvent);
    }
}

$.isScrollBottom = function(_y) {
    return ( (_y >= ($.scrollBottomY-25)) ? true : false );
}

/*
 * Bootstrap
 */
$.init();<commit_msg>fix the javascript conditional, commas were a typo. Also add role error highlighting<commit_after>/*
    7Breaths
    An application to simplify the clinical measurement of a person's respiratory rate
    Copyright (C) 2013  Neville Dastur neville [at] clinsoftsolutions.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
    INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
    PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
    FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

var APP = Alloy.Globals.APP;

if(OS_ANDROID){
    Alloy = require("alloy")
    _ = require("alloy/underscore")._
}

$.DEFAULT_ROLE_TEXT = "Please choose one ...";

var dataStore = require('datastore');

var ARGS = arguments[0] || {};
$.reachedBottom = false;
$.scrollBottomY = 0;

$.init = function() {
    var htmlfile = Ti.Filesystem.getFile(Ti.Filesystem.resourcesDirectory, "/tandc.html");
    var html = htmlfile.read().text;
    $.styledlabel.html = html;

    $.roleLabel.text = $.DEFAULT_ROLE_TEXT;

    $.reg_info.text = "Registration is entirely optional, but allows us to better"
    + " understand the data collected and also allows us send feedback to you.";

    Ti.App.addEventListener("androidback" , function() {
        // TODO don't allow close unless ok or cancel selected, i.e. prevent normal back button behaviour
        //this.close();
    });

    $.styledlabel.addEventListener("postlayout",function(e){
        $.scrollBottomY = e.source.getRect().height - $.ScrollWrapper.getSize().height;
        Ti.API.debug("Set $.scrollBottomY = " + $.scrollBottomY);
    });

    $.ScrollWrapper.addEventListener("scroll",$.scrollWrapper_ScrollEvent);

    $.accept_but.addEventListener("click",function(e){
        if ($.reachedBottom === false) {
            Ti.Analytics.featureEvent('APP:Tried_TandC_Accepted');
            alert("Please scroll down through all the Terms and Conditions before accepting them. Thank you.")
            return;
        }
        Ti.Analytics.featureEvent("APP:TandC_ACCEPTED");
        Ti.App.Properties.setBool("APP:TandC_ACCEPTED", true);
        $.scrollableView.setCurrentPage(1);
    });

    $.reject_but.addEventListener("click",function(e){
        Ti.Analytics.featureEvent('APP:TandC_Rejected');
        alert("Thank you for your interest in 7Breaths. As the terms are not acceptable please un-install the application.")
    });

    $.rolePickerWrapper.addEventListener("click",function(e){
        Ti.API.debug("rolePickerWrapper click")
        $.rolePickerWrapper.visible = false;
    });

    $.rolePicker.addEventListener("click", function(e){
        $.reg_firstname.blur();
        $.reg_surname.blur();
        $.reg_email.blur();
        $.rolePickerWrapper.visible = true;
    });

    $.rolePickerControl.addEventListener("change",function(e){
        Ti.API.debug("Click on picker row: " + e.row.title);
    });

    $.select_role_but.addEventListener("click",function(e){
        Ti.API.debug("Picker row selected: " + $.rolePickerControl.getSelectedRow(0).title);
        $.roleLabel.text = $.rolePickerControl.getSelectedRow(0).title;
    });

    $.register_but.addEventListener("click",function(e){
        var validate_msg = $.Validates();
        if(0 === validate_msg.length) {
            dataStore.RegisterUser(reg_email.value, reg_firstname.value, reg_surname.value,
                $.roleLabel.text);
            $.Window.close();
        }
        else {
            alert(validate_msg);
        }
    });

    $.skip_but.addEventListener("click",function(e){
        var _skipCount = Ti.App.Properties.getInt("APP:REG_SKIP_COUNT", 0) + 1;
        Ti.App.Properties.setInt("APP:REG_SKIP_COUNT", _skipCount);
        if (_skipCount < 3) {
            // We only prompt the user twice for registration if skipped
            // and with increasing intervals
            Ti.App.Properties.setInt("APP:REG_COUNTDOWN", _skipCount * 2);
        }
        $.Window.close();
    });

    // If T&C already accepted then go straight to registration page
    if (Ti.App.Properties.getBool("APP:TandC_ACCEPTED", false)) {
        $.scrollableView.setCurrentPage(1);
    }

}

/**
 * Validate the fields
 * If fails then returns a message. So emmpty string indicates success
 */
$.Validates = function() {
    var msg = "";
    if ( $.reg_email.value.length < 5
        || $.reg_firstname.value.length < 2
        || $.reg_surname.value.length < 2
        || $.roleLabel.text === $.DEFAULT_ROLE_TEXT) {

        msg += "All fields require a value please.\n";

        if ( $.reg_email.value.length < 5) {
            $.reg_email.borderColor = "#f00";
        }
        if ( $.reg_firstname.value.length < 5) {
            $.reg_firstname.borderColor = "#f00";
        }
        if ( $.reg_surname.value.length < 5) {
            $.reg_surname.borderColor = "#f00";
        }
        if ($.roleLabel.text === $.DEFAULT_ROLE_TEXT) {
            $.rolePicker.borderColor = "#f00";
        }
    }

    var reg = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;

    if($.reg_email.value.length >= 5 && reg.test($.reg_email.value) == false) {
        msg += "The email address appears to be invalid. Please correct";
        $.reg_email.borderColor = "#f00";
    }

    return msg;
}

$.scrollWrapper_ScrollEvent = function(_event) {
    //Ti.API.info("Scroll x="+_event.x+" y="+_event.y);
    if( $.isScrollBottom(_event.y) ) {
        Ti.API.info("ScrollView reached the bottom.");
        $.reachedBottom = true;
        // Don't need to listen any more
        $.ScrollWrapper.removeEventListener("scroll",$.scrollWrapper_ScrollEvent);
    }
}

$.isScrollBottom = function(_y) {
    return ( (_y >= ($.scrollBottomY-25)) ? true : false );
}

/*
 * Bootstrap
 */
$.init();<|endoftext|>


<commit_before>var ogreCompany = {
	init : function() {
		var newOgre = newElm('div');
		newOgre.id = 'newOgreDiv';
		newOgre.appendChild(textNode("Choose an Ogre:"));

		for(var type in ogreTypes)
		{
			var newOgreType = newElm('button');
			newOgreType.id = 'new_'+type;
			newOgreType.value = type;
			newOgreType.appendChild(textNode(ogreTypes[type].name));

			newOgre.appendChild(newOgreType);
		}

		document.body.appendChild(newOgre);
	}
}

<commit_msg>Framework in place for Choose Ogre buttons to generate a new Ogre<commit_after>var ogreCompany = {
	init : function() {
		var newOgre = newElm('div');
		newOgre.id = 'newOgreDiv';
		newOgre.appendChild(textNode("Choose an Ogre:"));

		for(var type in ogreTypes)
		{
			var newOgreType = newElm('button');
			newOgreType.id = 'new_'+type;
			newOgreType.value = type;
			newOgreType.appendChild(textNode(ogreTypes[type].name));
			newOgreType.onclick = function(){ogreCompany.addOgre(this.value);};

			newOgre.appendChild(newOgreType);
		}

		document.body.appendChild(newOgre);
	},

	addOgre : function(type) {
		if(ogreTypes[type] == undefined)
		{
			console.log("Unknown Ogre type: "+type);
			return false;
		}

		alert('Making new Ogre '+ogreTypes[type].name);
	}
}

<|endoftext|>


<commit_before>/**
 * Resources
 *
 * https://gist.github.com/2489540
 *
 */

/*jshint node: true */
/*global config:true, task:true, process:true*/
module.exports = function( grunt ) {

	// readOptionalJSON
	// by Ben Alman
	// https://gist.github.com/2876125
	function readOptionalJSON( filepath ) {
		var data = {};
		try {
			data = grunt.file.readJSON( filepath );
			grunt.verbose.write( "Reading " + filepath + "..." ).ok();
		} catch(e) {}
		return data;
	}

	var task = grunt.task;
	var file = grunt.file;
	var utils = grunt.utils;
	var log = grunt.log;
	var verbose = grunt.verbose;
	var fail = grunt.fail;
	var option = grunt.option;
	var config = grunt.config;
	var template = grunt.template;
	var distpaths = [
		"dist/jquery.js",
		"dist/jquery.min.js"
	];

	grunt.initConfig({
		pkg: "<json:package.json>",
		dst: readOptionalJSON("dist/.destination.json"),
		meta: {
			banner: "/*! jQuery v@<%= pkg.version %> jquery.com | jquery.org/license */"
		},
		compare_size: {
			files: distpaths
		},
		selector: {
			"src/selector.js": [
				"src/sizzle-jquery.js",
				"src/sizzle/sizzle.js"
			]
		},
		build: {
			"dist/jquery.js": [
				"src/intro.js",
				"src/core.js",
				"src/callbacks.js",
				"src/deferred.js",
				"src/support.js",
				"src/data.js",
				"src/queue.js",
				"src/attributes.js",
				"src/event.js",
				"src/selector.js",
				"src/traversing.js",
				"src/manipulation.js",

				{ flag: "deprecated", src: "src/deprecated.js" },
				{ flag: "css", src: "src/css.js" },
				{ flag: "ajax", src: "src/ajax.js" },
				{ flag: "ajax/jsonp", src: "src/ajax/jsonp.js", needs: [ "ajax", "ajax/script" ]  },
				{ flag: "ajax/script", src: "src/ajax/script.js", needs: ["ajax"]  },
				{ flag: "ajax/xhr", src: "src/ajax/xhr.js", needs: ["ajax"]  },
				{ flag: "effects", src: "src/effects.js", needs: ["css"] },
				{ flag: "offset", src: "src/offset.js", needs: ["css"] },
				{ flag: "dimensions", src: "src/dimensions.js", needs: ["css"] },

				"src/exports.js",
				"src/outro.js"
			]
		},
		min: {
			"dist/jquery.min.js": [ "<banner>", "dist/jquery.js" ]
		},

		lint: {
			dist: "dist/jquery.js",
			grunt: "grunt.js",
			tests: "test/unit/**/*.js"
		},

		jshint: (function() {
			function jshintrc( path ) {
				return readOptionalJSON( (path || "") + ".jshintrc" ) || {};
			}

			return {
				options: jshintrc(),
				dist: jshintrc( "src/" ),
				tests: jshintrc( "test/" )
			};
		})(),

		qunit: {
			files: "test/index.html"
		},
		watch: {
			files: [
				"<config:lint.dist>", "<config:lint.grunt>", "<config:lint.tests>",
				"src/**/*.js"
			],
			tasks: "dev"
		},
		uglify: {}
	});

	// Default grunt.
	grunt.registerTask( "default", "submodules selector build:*:* lint min dist:* compare_size" );

	// Short list as a high frequency watch task
	grunt.registerTask( "dev", "selector build:*:* lint" );

	// Load the "compare_size" task from NPM packages
	grunt.loadNpmTasks("grunt-compare-size");

	grunt.registerTask( "testswarm", function( commit, configFile ) {
		var testswarm = require( "testswarm" ),
			testUrls = [],
			config = grunt.file.readJSON( configFile ).jquery;
		var tests = "ajax attributes callbacks core css data deferred dimensions effects event manipulation offset queue selector support traversing".split( " " );
		tests.forEach(function( test ) {
			testUrls.push( config.testUrl + commit + "/test/index.html?module=" + test );
		});
		testswarm({
			url: config.swarmUrl,
			pollInterval: 10000,
			timeout: 1000 * 60 * 30,
			done: this.async()
		}, {
			authUsername: config.authUsername,
			authToken: config.authToken,
			jobName: 'jQuery commit #' + commit.substr( 0, 10 ) + '',
			runMax: config.runMax,
			"runNames[]": tests,
			"runUrls[]": testUrls,
			"browserSets[]": ["popular"]
		});
	});

	// Build src/selector.js
	grunt.registerMultiTask( "selector", "Build src/selector.js", function() {

		var name = this.file.dest,
				files = this.file.src,
				sizzle = {
					api: file.read( files[0] ),
					src: file.read( files[1] )
				},
        compiled, parts;

    /**

      sizzle-jquery.js -> sizzle between "EXPOSE" blocks,
      replace define & window.Sizzle assignment

      // EXPOSE
      if ( typeof define === "function" && define.amd ) {
        define(function() { return Sizzle; });
      } else {
        window.Sizzle = Sizzle;
      }
      // EXPOSE

      Becomes...

      Sizzle.attr = jQuery.attr;
      jQuery.find = Sizzle;
      jQuery.expr = Sizzle.selectors;
      jQuery.expr[":"] = jQuery.expr.pseudos;
      jQuery.unique = Sizzle.uniqueSort;
      jQuery.text = Sizzle.getText;
      jQuery.isXMLDoc = Sizzle.isXML;
      jQuery.contains = Sizzle.contains;

     */

    // Break into 3 pieces
    parts = sizzle.src.split("// EXPOSE");
    // Replace the if/else block with api
    parts[1] = sizzle.api;
    // Rejoin the pieces
    compiled = parts.join("");

		verbose.write("Injected sizzle-jquery.js into sizzle.js");

		// Write concatenated source to file
		file.write( name, compiled );

		// Fail task if errors were logged.
		if ( this.errorCount ) {
			return false;
		}

		// Otherwise, print a success message.
		log.writeln( "File '" + name + "' created." );
	});

	// Special "alias" task to make custom build creation less grawlix-y
	grunt.registerTask( "custom", function() {
		var done = this.async(),
				args = [].slice.call(arguments),
				modules = args.length ? args[0].replace(/,/g, ":") : "";

		// Translation example
		//
		//   grunt custom:+ajax,-dimensions,-effects,-offset
		//
		// Becomes:
		//
		//   grunt build:*:*:-ajax:-dimensions:-effects:-offset

		grunt.log.writeln( "Creating custom build...\n" );

		grunt.utils.spawn({
			cmd: "grunt",
			args: [ "build:*:*:" + modules ]
		}, function( err, result ) {
			if ( err ) {
				grunt.verbose.error();
				done( err );
				return;
			}

			grunt.log.writeln( result.replace("Done, without errors.", "") );

			done();
		});
	});

	// Special concat/build task to handle various jQuery build requirements
	//
	grunt.registerMultiTask(
		"build",
		"Concatenate source (include/exclude modules with +/- flags), embed date/version",
		function() {
			// Concat specified files.
			var i,
				compiled = "",
				modules = this.flags,
				explicit = Object.keys(modules).length > 1,
				optIn = !modules["*"],
				name = this.file.dest,
				excluded = {},
				version = config( "pkg.version" ),
				excluder = function( flag, needsFlag ) {
					// explicit > implicit, so set this first and let it be overridden by explicit
					if ( optIn && !modules[ flag ] && !modules[ "+" + flag ] ) {
						excluded[ flag ] = false;
					}

					if ( excluded[ needsFlag ] || modules[ "-" + flag ] ) {
						// explicit exclusion from flag or dependency
						excluded[ flag ] = true;
					} else if ( modules[ "+" + flag ] && ( excluded[ needsFlag ] === false ) ) {
						// explicit inclusion from flag or dependency overriding a weak inclusion
						delete excluded[ needsFlag ];
					}
				};

			if ( process.env.COMMIT ) {
				version += " " + process.env.COMMIT;
			}

			// figure out which files to exclude based on these rules in this order:
			//  explicit > implicit (explicit also means a dependency/dependent that was explicit)
			//  exclude > include
			// examples:
			//  *:                 none (implicit exclude)
			//  *:*                all (implicit include)
			//  *:*:-effects       all except effects (explicit > implicit)
			//  *:*:-css           all except css and its deps (explicit)
			//  *:*:-css:+effects  all except css and its deps (explicit exclude from dep. trumps explicit include)
			//  *:+effects         none except effects and its deps (explicit include from dep. trumps implicit exclude)
			this.file.src.forEach(function( filepath ) {
				var flag = filepath.flag;

				if ( flag ) {

					excluder(flag);

					// check for dependencies
					if ( filepath.needs ) {
						filepath.needs.forEach(function( needsFlag ) {
							excluder( flag, needsFlag );
						});
					}
				}
			});

			// conditionally concatenate source
			this.file.src.forEach(function( filepath ) {
				var flag = filepath.flag,
						specified = false,
						omit = false,
						message = "";

				if ( flag ) {
					if ( excluded[ flag ] !== undefined ) {
						message = ( "Excluding " + flag ).red;
						specified = true;
						omit = true;
					} else {
						message = ( "Including " + flag ).green;

						// If this module was actually specified by the
						// builder, then st the flag to include it in the
						// output list
						if ( modules[ "+" + flag ] ) {
							specified = true;
						}
					}

					// Only display the inclusion/exclusion list when handling
					// an explicit list.
					//
					// Additionally, only display modules that have been specified
					// by the user
					if ( explicit && specified ) {
						grunt.log.writetableln([ 27, 30 ], [
							message,
							( "(" + filepath.src + ")").grey
						]);
					}

					filepath = filepath.src;
				}

				if ( !omit ) {
					compiled += file.read( filepath );
				}
			});

			// Embed Date
			// Embed Version
			compiled = compiled.replace( "@DATE", new Date() )
				.replace( /@VERSION/g, version );

			// Write concatenated source to file
			file.write( name, compiled );

			// Fail task if errors were logged.
			if ( this.errorCount ) {
				return false;
			}

			// Otherwise, print a success message.
			log.writeln( "File '" + name + "' created." );
		});

	grunt.registerTask( "submodules", function() {
		var done = this.async();

		grunt.verbose.write( "Updating submodules..." );

		// TODO: migrate remaining `make` to grunt tasks
		//
		grunt.utils.spawn({
			cmd: "make"
		}, function( err, result ) {
			if ( err ) {
				grunt.verbose.error();
				done( err );
				return;
			}

			grunt.log.writeln( result );

			done();
		});
	});

	// Allow custom dist file locations
	grunt.registerTask( "dist", function() {
		var flags, paths, stored;

		// Check for stored destination paths
		// ( set in dist/.destination.json )
		stored = Object.keys( config("dst") );

		// Allow command line input as well
		flags = Object.keys( this.flags );

		// Combine all output target paths
		paths = [].concat( stored, flags ).filter(function( path ) {
			return path !== "*";
		});

		// Proceed only if there are actual
		// paths to write to
		if ( paths.length ) {

			// 'distpaths' is declared at the top of the
			// module.exports function scope. It is an array
			// of default files that jQuery creates
			distpaths.forEach(function( filename ) {
				paths.forEach(function( path ) {
					var created;

					if ( !/\/$/.test( path ) ) {
						path += "/";
					}

					created = path + filename.replace( "dist/", "" );

					if ( !/^\//.test( path ) ) {
						log.error( "File '" + created + "' was NOT created." );
						return;
					}

					file.write( created, file.read(filename) );

					log.writeln( "File '" + created + "' created." );
				});
			});
		}
	});
};
<commit_msg>Fixes indentation in grunt.js<commit_after>/**
 * Resources
 *
 * https://gist.github.com/2489540
 *
 */

/*jshint node: true */
/*global config:true, task:true, process:true*/
module.exports = function( grunt ) {

	// readOptionalJSON
	// by Ben Alman
	// https://gist.github.com/2876125
	function readOptionalJSON( filepath ) {
		var data = {};
		try {
			data = grunt.file.readJSON( filepath );
			grunt.verbose.write( "Reading " + filepath + "..." ).ok();
		} catch(e) {}
		return data;
	}

	var task = grunt.task;
	var file = grunt.file;
	var utils = grunt.utils;
	var log = grunt.log;
	var verbose = grunt.verbose;
	var fail = grunt.fail;
	var option = grunt.option;
	var config = grunt.config;
	var template = grunt.template;
	var distpaths = [
		"dist/jquery.js",
		"dist/jquery.min.js"
	];

	grunt.initConfig({
		pkg: "<json:package.json>",
		dst: readOptionalJSON("dist/.destination.json"),
		meta: {
			banner: "/*! jQuery v@<%= pkg.version %> jquery.com | jquery.org/license */"
		},
		compare_size: {
			files: distpaths
		},
		selector: {
			"src/selector.js": [
				"src/sizzle-jquery.js",
				"src/sizzle/sizzle.js"
			]
		},
		build: {
			"dist/jquery.js": [
				"src/intro.js",
				"src/core.js",
				"src/callbacks.js",
				"src/deferred.js",
				"src/support.js",
				"src/data.js",
				"src/queue.js",
				"src/attributes.js",
				"src/event.js",
				"src/selector.js",
				"src/traversing.js",
				"src/manipulation.js",

				{ flag: "deprecated", src: "src/deprecated.js" },
				{ flag: "css", src: "src/css.js" },
				{ flag: "ajax", src: "src/ajax.js" },
				{ flag: "ajax/jsonp", src: "src/ajax/jsonp.js", needs: [ "ajax", "ajax/script" ]  },
				{ flag: "ajax/script", src: "src/ajax/script.js", needs: ["ajax"]  },
				{ flag: "ajax/xhr", src: "src/ajax/xhr.js", needs: ["ajax"]  },
				{ flag: "effects", src: "src/effects.js", needs: ["css"] },
				{ flag: "offset", src: "src/offset.js", needs: ["css"] },
				{ flag: "dimensions", src: "src/dimensions.js", needs: ["css"] },

				"src/exports.js",
				"src/outro.js"
			]
		},
		min: {
			"dist/jquery.min.js": [ "<banner>", "dist/jquery.js" ]
		},

		lint: {
			dist: "dist/jquery.js",
			grunt: "grunt.js",
			tests: "test/unit/**/*.js"
		},

		jshint: (function() {
			function jshintrc( path ) {
				return readOptionalJSON( (path || "") + ".jshintrc" ) || {};
			}

			return {
				options: jshintrc(),
				dist: jshintrc( "src/" ),
				tests: jshintrc( "test/" )
			};
		})(),

		qunit: {
			files: "test/index.html"
		},
		watch: {
			files: [
				"<config:lint.dist>", "<config:lint.grunt>", "<config:lint.tests>",
				"src/**/*.js"
			],
			tasks: "dev"
		},
		uglify: {}
	});

	// Default grunt.
	grunt.registerTask( "default", "submodules selector build:*:* lint min dist:* compare_size" );

	// Short list as a high frequency watch task
	grunt.registerTask( "dev", "selector build:*:* lint" );

	// Load the "compare_size" task from NPM packages
	grunt.loadNpmTasks("grunt-compare-size");

	grunt.registerTask( "testswarm", function( commit, configFile ) {
		var testswarm = require( "testswarm" ),
			testUrls = [],
			config = grunt.file.readJSON( configFile ).jquery;
		var tests = "ajax attributes callbacks core css data deferred dimensions effects event manipulation offset queue selector support traversing".split( " " );
		tests.forEach(function( test ) {
			testUrls.push( config.testUrl + commit + "/test/index.html?module=" + test );
		});
		testswarm({
			url: config.swarmUrl,
			pollInterval: 10000,
			timeout: 1000 * 60 * 30,
			done: this.async()
		}, {
			authUsername: config.authUsername,
			authToken: config.authToken,
			jobName: 'jQuery commit #' + commit.substr( 0, 10 ) + '',
			runMax: config.runMax,
			"runNames[]": tests,
			"runUrls[]": testUrls,
			"browserSets[]": ["popular"]
		});
	});

	// Build src/selector.js
	grunt.registerMultiTask( "selector", "Build src/selector.js", function() {

		var name = this.file.dest,
				files = this.file.src,
				sizzle = {
					api: file.read( files[0] ),
					src: file.read( files[1] )
				},
				compiled, parts;

		/**

			sizzle-jquery.js -> sizzle between "EXPOSE" blocks,
			replace define & window.Sizzle assignment

			// EXPOSE
			if ( typeof define === "function" && define.amd ) {
				define(function() { return Sizzle; });
			} else {
				window.Sizzle = Sizzle;
			}
			// EXPOSE

			Becomes...

			Sizzle.attr = jQuery.attr;
			jQuery.find = Sizzle;
			jQuery.expr = Sizzle.selectors;
			jQuery.expr[":"] = jQuery.expr.pseudos;
			jQuery.unique = Sizzle.uniqueSort;
			jQuery.text = Sizzle.getText;
			jQuery.isXMLDoc = Sizzle.isXML;
			jQuery.contains = Sizzle.contains;

		 */

		// Break into 3 pieces
		parts = sizzle.src.split("// EXPOSE");
		// Replace the if/else block with api
		parts[1] = sizzle.api;
		// Rejoin the pieces
		compiled = parts.join("");

		verbose.write("Injected sizzle-jquery.js into sizzle.js");

		// Write concatenated source to file
		file.write( name, compiled );

		// Fail task if errors were logged.
		if ( this.errorCount ) {
			return false;
		}

		// Otherwise, print a success message.
		log.writeln( "File '" + name + "' created." );
	});

	// Special "alias" task to make custom build creation less grawlix-y
	grunt.registerTask( "custom", function() {
		var done = this.async(),
				args = [].slice.call(arguments),
				modules = args.length ? args[0].replace(/,/g, ":") : "";

		// Translation example
		//
		//   grunt custom:+ajax,-dimensions,-effects,-offset
		//
		// Becomes:
		//
		//   grunt build:*:*:-ajax:-dimensions:-effects:-offset

		grunt.log.writeln( "Creating custom build...\n" );

		grunt.utils.spawn({
			cmd: "grunt",
			args: [ "build:*:*:" + modules ]
		}, function( err, result ) {
			if ( err ) {
				grunt.verbose.error();
				done( err );
				return;
			}

			grunt.log.writeln( result.replace("Done, without errors.", "") );

			done();
		});
	});

	// Special concat/build task to handle various jQuery build requirements
	//
	grunt.registerMultiTask(
		"build",
		"Concatenate source (include/exclude modules with +/- flags), embed date/version",
		function() {
			// Concat specified files.
			var i,
				compiled = "",
				modules = this.flags,
				explicit = Object.keys(modules).length > 1,
				optIn = !modules["*"],
				name = this.file.dest,
				excluded = {},
				version = config( "pkg.version" ),
				excluder = function( flag, needsFlag ) {
					// explicit > implicit, so set this first and let it be overridden by explicit
					if ( optIn && !modules[ flag ] && !modules[ "+" + flag ] ) {
						excluded[ flag ] = false;
					}

					if ( excluded[ needsFlag ] || modules[ "-" + flag ] ) {
						// explicit exclusion from flag or dependency
						excluded[ flag ] = true;
					} else if ( modules[ "+" + flag ] && ( excluded[ needsFlag ] === false ) ) {
						// explicit inclusion from flag or dependency overriding a weak inclusion
						delete excluded[ needsFlag ];
					}
				};

			if ( process.env.COMMIT ) {
				version += " " + process.env.COMMIT;
			}

			// figure out which files to exclude based on these rules in this order:
			//  explicit > implicit (explicit also means a dependency/dependent that was explicit)
			//  exclude > include
			// examples:
			//  *:                 none (implicit exclude)
			//  *:*                all (implicit include)
			//  *:*:-effects       all except effects (explicit > implicit)
			//  *:*:-css           all except css and its deps (explicit)
			//  *:*:-css:+effects  all except css and its deps (explicit exclude from dep. trumps explicit include)
			//  *:+effects         none except effects and its deps (explicit include from dep. trumps implicit exclude)
			this.file.src.forEach(function( filepath ) {
				var flag = filepath.flag;

				if ( flag ) {

					excluder(flag);

					// check for dependencies
					if ( filepath.needs ) {
						filepath.needs.forEach(function( needsFlag ) {
							excluder( flag, needsFlag );
						});
					}
				}
			});

			// conditionally concatenate source
			this.file.src.forEach(function( filepath ) {
				var flag = filepath.flag,
						specified = false,
						omit = false,
						message = "";

				if ( flag ) {
					if ( excluded[ flag ] !== undefined ) {
						message = ( "Excluding " + flag ).red;
						specified = true;
						omit = true;
					} else {
						message = ( "Including " + flag ).green;

						// If this module was actually specified by the
						// builder, then st the flag to include it in the
						// output list
						if ( modules[ "+" + flag ] ) {
							specified = true;
						}
					}

					// Only display the inclusion/exclusion list when handling
					// an explicit list.
					//
					// Additionally, only display modules that have been specified
					// by the user
					if ( explicit && specified ) {
						grunt.log.writetableln([ 27, 30 ], [
							message,
							( "(" + filepath.src + ")").grey
						]);
					}

					filepath = filepath.src;
				}

				if ( !omit ) {
					compiled += file.read( filepath );
				}
			});

			// Embed Date
			// Embed Version
			compiled = compiled.replace( "@DATE", new Date() )
				.replace( /@VERSION/g, version );

			// Write concatenated source to file
			file.write( name, compiled );

			// Fail task if errors were logged.
			if ( this.errorCount ) {
				return false;
			}

			// Otherwise, print a success message.
			log.writeln( "File '" + name + "' created." );
		});

	grunt.registerTask( "submodules", function() {
		var done = this.async();

		grunt.verbose.write( "Updating submodules..." );

		// TODO: migrate remaining `make` to grunt tasks
		//
		grunt.utils.spawn({
			cmd: "make"
		}, function( err, result ) {
			if ( err ) {
				grunt.verbose.error();
				done( err );
				return;
			}

			grunt.log.writeln( result );

			done();
		});
	});

	// Allow custom dist file locations
	grunt.registerTask( "dist", function() {
		var flags, paths, stored;

		// Check for stored destination paths
		// ( set in dist/.destination.json )
		stored = Object.keys( config("dst") );

		// Allow command line input as well
		flags = Object.keys( this.flags );

		// Combine all output target paths
		paths = [].concat( stored, flags ).filter(function( path ) {
			return path !== "*";
		});

		// Proceed only if there are actual
		// paths to write to
		if ( paths.length ) {

			// 'distpaths' is declared at the top of the
			// module.exports function scope. It is an array
			// of default files that jQuery creates
			distpaths.forEach(function( filename ) {
				paths.forEach(function( path ) {
					var created;

					if ( !/\/$/.test( path ) ) {
						path += "/";
					}

					created = path + filename.replace( "dist/", "" );

					if ( !/^\//.test( path ) ) {
						log.error( "File '" + created + "' was NOT created." );
						return;
					}

					file.write( created, file.read(filename) );

					log.writeln( "File '" + created + "' created." );
				});
			});
		}
	});
};
<|endoftext|>


<commit_before>module.exports = function(grunt) {

  /**
   * Configuration
   */

  grunt.config.init({

    // Constants
    dirs: {
      client    : __dirname + '/src/client/',
      lib       : __dirname + '/components/',
      server    : __dirname + '/src/server/',
      web       : __dirname + '/public/',
      build     : __dirname + '/public/build/'
    },

    files: {
      all       : '**/*',
      img       : 'img/**/*',
      js        : '**/*.js',
      less      : 'less/**/*.less',
      html      : '**/*.html'
    },

    // Common
    pkg         : grunt.file.readJSON('package.json'),
    meta        : {
      banner    : '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - '                   +
                  '<%= grunt.template.today("yyyy-mm-dd") %>\\n'                                 +
                  '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>'                       +
                  '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
                  ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
    },
    clean:      ['<%= dirs.build %>'],
    watch:      {
      all:      {
        files   : ['grunt.js'
                  ,'<%= dirs.server + files.all %>'
                  ,'<%= dirs.client %>/app/<%= files.all %>'],
        tasks   : ['lint', 'compile', 'concat:app', 'copy:app', 'express-server', 'reload'],
        options : { interrupt: true }
      }
    },

    // Code validation
    lint:       {
      files     : ['grunt.js'
                  ,'<%= dirs.server + files.js %>'
                  ,'<%= dirs.client %>/app/<%= files.js %>']
    },
    jshint:     {
      options:  {
        es5:      true,
        laxcomma: true
      }
    },

    // Compilation
    less:       {
      app:      {
        src     : ['<%= dirs.lib %>/github-fork-ribbon-css/gh-fork-ribbon.css'
                  ,'<%= dirs.client %>/app/less/app.less'],
        dest    : '<%= dirs.build %>/css/app.css'
      }
    },
    requirejs:  {
      compile:  {
        options:{
          cssIn : '<%= less.app.dest %>',
          out   : '<%= less.app.dest %>'
        }
      }
    },

    // Concatenation
    copy:       {
      app:      {
        options : {
          cwd   : '<%= dirs.client %>/app'
        },
        files   : { '<%= dirs.build %>img/': '<%= dirs.client %>/app/<%= files.img %>' }
      },
      lib:      {
        options : {
          cwd   : '<%= dirs.client %>/components'
        },
        files   : { '<%= dirs.build %>/img/': '<%= dirs.lib %>/bootstrap/<%= files.img %>' }
      }
    },
    ngtemplates:{
      app:      {
        options : {
          base  : '<%= dirs.client %>/app'
        },
        src     : ['<%= dirs.client %>/app/<%= files.html %>'],
        dest    : '<%= dirs.build %>/js/templates.js'
      }
    },
    concat:     {
      angular:  {
        src     : ['<%= dirs.lib %>/angular-1.0.3/angular.js'
                  ,'<%= dirs.lib %>/angular-1.0.3/angular-resource.js'
                  ,'<%= dirs.lib %>/angular-strap/dist/angular-strap.js'],
        dest    : '<%= dirs.build %>/js/lib/angular.js'
      },
      app:      {
        src     : ['<banner:meta.banner>'
                  ,'<%= dirs.client %>/app/<%= files.js %>'
                  ,'<%= ngtemplates.app.dest %>'],
        dest    : '<%= dirs.build %>/js/app.js'
      },
      all:      {
        src     : ['<banner:meta.banner>'
                  ,'<%= concat.angular.dest %>'
                  ,'<%= concat.app.dest %>'],
        dest    : '<%= dirs.build %>/js/all.js'
      }
    },

    // Minification
    cssmin:     {
      app:      {
        src     : ['<banner:meta.banner>', '<%= less.app.dest %>'],
        dest    : '<%= less.app.dest.replace(".css", ".min.css") %>'
      }
    },
    smushit:    {
      all:      {
        src     : '<%= dirs.build %>/img'
      }
    },
    min:        {
      angular:  {
        src     : '<%= concat.angular.dest %>',
        dest    : '<%= concat.angular.dest.replace(".js", ".min.js") %>'
      },
      app:      {
        src     : ['<banner:meta.banner>', '<%= concat.app.dest %>'],
        dest    : '<%= concat.app.dest.replace(".js", ".min.js") %>'
      },
      all:      {
        src     : ['<banner:meta.banner>', '<%= concat.all.dest %>'],
        dest    : '<%= concat.all.dest.replace(".js", ".min.js") %>'
      }
    },

    // Live-Reload Reverse-Proxy Server
    open:       {
      dev:      {
        url     : 'http://localhost:' + (process.env.PORT || 3000) + '/'
      }
    },
    reload:     {
      port      : process.env.PORT || 3000, // Browser-targeted port

      proxy:    {
        host    : 'localhost',
        port    : 3001 // Source port
      }
    },
    server:     {
      script    : '<%= dirs.server %>/server.js',
      port      : 3001 // Source Port
    }

  });

  /**
   * Dependencies
   */

  grunt.loadNpmTasks('grunt-angular-templates');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  grunt.loadNpmTasks('grunt-css');
  grunt.loadNpmTasks('grunt-open');
  grunt.loadNpmTasks('grunt-reload');
  grunt.loadNpmTasks('grunt-smushit');

  /**
   * Custom tasks
   */

  grunt.loadTasks('tasks');

  /**
   * Tasks
   */

  grunt.registerTask('default', ['lint', 'compile', 'concat', 'copy']);
  grunt.registerTask('compile', ['less', 'requirejs', 'ngtemplates']);
  grunt.registerTask('build',   ['clean', 'default', 'minify']);
  grunt.registerTask('minify',  ['cssmin', 'min', 'smushit']);
  grunt.registerTask('server',  ['default', 'express-server', 'reload', 'watch']);

};
<commit_msg>Fix copy:lib path<commit_after>module.exports = function(grunt) {

  /**
   * Configuration
   */

  grunt.config.init({

    // Constants
    dirs: {
      client    : __dirname + '/src/client/',
      lib       : __dirname + '/src/client/components/',
      server    : __dirname + '/src/server/',
      web       : __dirname + '/public/',
      build     : __dirname + '/public/build/'
    },

    files: {
      all       : '**/*',
      img       : 'img/**/*',
      js        : '**/*.js',
      less      : 'less/**/*.less',
      html      : '**/*.html'
    },

    // Common
    pkg         : grunt.file.readJSON('package.json'),
    meta        : {
      banner    : '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - '                   +
                  '<%= grunt.template.today("yyyy-mm-dd") %>\\n'                                 +
                  '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>'                       +
                  '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
                  ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
    },
    clean:      ['<%= dirs.build %>'],
    watch:      {
      all:      {
        files   : ['grunt.js'
                  ,'<%= dirs.server + files.all %>'
                  ,'<%= dirs.client %>/app/<%= files.all %>'],
        tasks   : ['lint', 'compile', 'concat:app', 'copy:app', 'express-server', 'reload'],
        options : { interrupt: true }
      }
    },

    // Code validation
    lint:       {
      files     : ['grunt.js'
                  ,'<%= dirs.server + files.js %>'
                  ,'<%= dirs.client %>/app/<%= files.js %>']
    },
    jshint:     {
      options:  {
        es5:      true,
        laxcomma: true
      }
    },

    // Compilation
    less:       {
      app:      {
        src     : ['<%= dirs.lib %>/github-fork-ribbon-css/gh-fork-ribbon.css'
                  ,'<%= dirs.client %>/app/less/app.less'],
        dest    : '<%= dirs.build %>/css/app.css'
      }
    },
    requirejs:  {
      compile:  {
        options:{
          cssIn : '<%= less.app.dest %>',
          out   : '<%= less.app.dest %>'
        }
      }
    },

    // Concatenation
    copy:       {
      app:      {
        options : {
          cwd   : '<%= dirs.client %>/app'
        },
        files   : { '<%= dirs.build %>img/': '<%= dirs.client %>/app/<%= files.img %>' }
      },
      lib:      {
        options : {
          cwd   : '<%= dirs.lib %>'
        },
        files   : { '<%= dirs.build %>/img/': '<%= dirs.lib %>/bootstrap/<%= files.img %>' }
      }
    },
    ngtemplates:{
      app:      {
        options : {
          base  : '<%= dirs.client %>/app'
        },
        src     : ['<%= dirs.client %>/app/<%= files.html %>'],
        dest    : '<%= dirs.build %>/js/templates.js'
      }
    },
    concat:     {
      angular:  {
        src     : ['<%= dirs.lib %>/angular-1.0.3/angular.js'
                  ,'<%= dirs.lib %>/angular-1.0.3/angular-resource.js'
                  ,'<%= dirs.lib %>/angular-strap/dist/angular-strap.js'],
        dest    : '<%= dirs.build %>/js/lib/angular.js'
      },
      app:      {
        src     : ['<banner:meta.banner>'
                  ,'<%= dirs.client %>/app/<%= files.js %>'
                  ,'<%= ngtemplates.app.dest %>'],
        dest    : '<%= dirs.build %>/js/app.js'
      },
      all:      {
        src     : ['<banner:meta.banner>'
                  ,'<%= concat.angular.dest %>'
                  ,'<%= concat.app.dest %>'],
        dest    : '<%= dirs.build %>/js/all.js'
      }
    },

    // Minification
    cssmin:     {
      app:      {
        src     : ['<banner:meta.banner>', '<%= less.app.dest %>'],
        dest    : '<%= less.app.dest.replace(".css", ".min.css") %>'
      }
    },
    smushit:    {
      all:      {
        src     : '<%= dirs.build %>/img'
      }
    },
    min:        {
      angular:  {
        src     : '<%= concat.angular.dest %>',
        dest    : '<%= concat.angular.dest.replace(".js", ".min.js") %>'
      },
      app:      {
        src     : ['<banner:meta.banner>', '<%= concat.app.dest %>'],
        dest    : '<%= concat.app.dest.replace(".js", ".min.js") %>'
      },
      all:      {
        src     : ['<banner:meta.banner>', '<%= concat.all.dest %>'],
        dest    : '<%= concat.all.dest.replace(".js", ".min.js") %>'
      }
    },

    // Live-Reload Reverse-Proxy Server
    open:       {
      dev:      {
        url     : 'http://localhost:' + (process.env.PORT || 3000) + '/'
      }
    },
    reload:     {
      port      : process.env.PORT || 3000, // Browser-targeted port

      proxy:    {
        host    : 'localhost',
        port    : 3001 // Source port
      }
    },
    server:     {
      script    : '<%= dirs.server %>/server.js',
      port      : 3001 // Source Port
    }

  });

  /**
   * Dependencies
   */

  grunt.loadNpmTasks('grunt-angular-templates');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  grunt.loadNpmTasks('grunt-css');
  grunt.loadNpmTasks('grunt-open');
  grunt.loadNpmTasks('grunt-reload');
  grunt.loadNpmTasks('grunt-smushit');

  /**
   * Custom tasks
   */

  grunt.loadTasks('tasks');

  /**
   * Tasks
   */

  grunt.registerTask('default', ['lint', 'compile', 'concat', 'copy']);
  grunt.registerTask('compile', ['less', 'requirejs', 'ngtemplates']);
  grunt.registerTask('build',   ['clean', 'default', 'minify']);
  grunt.registerTask('minify',  ['cssmin', 'min', 'smushit']);
  grunt.registerTask('server',  ['default', 'express-server', 'reload', 'watch']);

};
<|endoftext|>