<commit_before>/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * 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.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $, localStorage */

/**
 * PreferencesManager
 *
 */
define(function (require, exports, module) {
    "use strict";

    var PreferenceStorage = require("preferences/PreferenceStorage").PreferenceStorage;

    var PREFERENCES_CLIENT_ID = "com.adobe.brackets." + module.id;

    // Private Properties
    var preferencesKey,
        prefStorage,
        persistentStorage,
        doLoadPreferences   = false;

    /**
     * Retreive preferences data for the given clientID.
     *
     * @param {string} clientID Unique identifier
     * @param {string} defaults Default preferences stored as JSON
     * @return {PreferenceStorage}
     */
    function getPreferenceStorage(clientID, defaults) {
        if ((clientID === undefined) || (clientID === null)) {
            console.error("Invalid clientID");
            return;
        }

        var prefs = prefStorage[clientID];

        if (prefs === undefined) {
            // create a new empty preferences object
            prefs = (defaults && JSON.stringify(defaults)) ? defaults : {};
            prefStorage[clientID] = prefs;
        } else if (defaults) {
            // add new defaults
            Object.keys(defaults).forEach(function (key) {
                if (prefs[key] === undefined) {
                    prefs[key] = defaults[key];
                }
            });
        }

        return new PreferenceStorage(clientID, prefs);
    }

    /**
     * Save all preference clients.
     */
    function savePreferences() {
        // save all preferences
        persistentStorage.setItem(preferencesKey, JSON.stringify(prefStorage));
    }

    /**
     * @private
     * Reset preferences and callbacks
     */
    function _reset() {
        prefStorage = {};

        // Note that storage.clear() is not used. Production and unit test code
        // both rely on the same backing storage but unique item keys.
        persistentStorage.setItem(preferencesKey, JSON.stringify(prefStorage));
    }

    /**
     * @private
     * Initialize persistent storage implementation
     */
    function _initStorage(storage) {
        persistentStorage = storage;

        if (doLoadPreferences) {
            prefStorage = JSON.parse(persistentStorage.getItem(preferencesKey));
        }

        // initialize empty preferences if none were found in storage
        if (!prefStorage) {
            _reset();
        }
    }

    /**
     * This method handles the copy of all old prefs to the new prefs
     * TODO: remove All calls to this function and the function itself
     *
     * @param {!PreferenceStorage} newPrefs The new PreferenceStorage
     * @param {!string} oldID The id of the old PreferenceStorage
     * @param {?obj} defaults The defaults to add
     */
    function handleClientIdChange(newPrefs, oldID, defaults) {
        var oldPrefs = getPreferenceStorage(oldID);

        defaults = defaults || {};

        if (!newPrefs.getValue("newClientID")) {
            var data = oldPrefs.getAllValues();

            if ($.isEmptyObject(data)) {
                data = defaults;
            }

            newPrefs.setAllValues(data, false);
            newPrefs.setValue("newClientID", true);
        }
        delete prefStorage[oldID];
    }

    // Check localStorage for a preferencesKey. Production and unit test keys
    // are used to keep preferences separate within the same storage implementation.
    preferencesKey = localStorage.getItem("preferencesKey");

    if (!preferencesKey) {
        // use default key if none is found
        preferencesKey = PREFERENCES_CLIENT_ID;
        doLoadPreferences = true;
    } else {
        // using a non-default key, check for additional settings
        doLoadPreferences = !!(localStorage.getItem("doLoadPreferences"));
    }

    //TODO: remove this preferences migration code
    if (!localStorage.getItem("newClientID")) {
        var oldPrefs = localStorage.getItem("com.adobe.brackets.preferences");
        localStorage.setItem(preferencesKey, oldPrefs);
        localStorage.setItem("newClientID", true);
    }
    // Use localStorage by default
    _initStorage(localStorage);

    // Public API
    exports.getPreferenceStorage    = getPreferenceStorage;
    exports.savePreferences         = savePreferences;
    exports.handleClientIdChange    = handleClientIdChange;

    // Unit test use only
    exports._reset                  = _reset;
});<commit_msg>Reverted change in PreferencesManager<commit_after>/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * 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.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $, localStorage */

/**
 * PreferencesManager
 *
 */
define(function (require, exports, module) {
    "use strict";

    var PreferenceStorage = require("preferences/PreferenceStorage").PreferenceStorage;

    var PREFERENCES_CLIENT_ID = "com.adobe.brackets.preferences";

    // Private Properties
    var preferencesKey,
        prefStorage,
        persistentStorage,
        doLoadPreferences   = false;

    /**
     * Retreive preferences data for the given clientID.
     *
     * @param {string} clientID Unique identifier
     * @param {string} defaults Default preferences stored as JSON
     * @return {PreferenceStorage}
     */
    function getPreferenceStorage(clientID, defaults) {
        if ((clientID === undefined) || (clientID === null)) {
            console.error("Invalid clientID");
            return;
        }

        var prefs = prefStorage[clientID];

        if (prefs === undefined) {
            // create a new empty preferences object
            prefs = (defaults && JSON.stringify(defaults)) ? defaults : {};
            prefStorage[clientID] = prefs;
        } else if (defaults) {
            // add new defaults
            Object.keys(defaults).forEach(function (key) {
                if (prefs[key] === undefined) {
                    prefs[key] = defaults[key];
                }
            });
        }

        return new PreferenceStorage(clientID, prefs);
    }

    /**
     * Save all preference clients.
     */
    function savePreferences() {
        // save all preferences
        persistentStorage.setItem(preferencesKey, JSON.stringify(prefStorage));
    }

    /**
     * @private
     * Reset preferences and callbacks
     */
    function _reset() {
        prefStorage = {};

        // Note that storage.clear() is not used. Production and unit test code
        // both rely on the same backing storage but unique item keys.
        persistentStorage.setItem(preferencesKey, JSON.stringify(prefStorage));
    }

    /**
     * @private
     * Initialize persistent storage implementation
     */
    function _initStorage(storage) {
        persistentStorage = storage;

        if (doLoadPreferences) {
            prefStorage = JSON.parse(persistentStorage.getItem(preferencesKey));
        }

        // initialize empty preferences if none were found in storage
        if (!prefStorage) {
            _reset();
        }
    }

    /**
     * This method handles the copy of all old prefs to the new prefs
     * TODO: remove All calls to this function and the function itself
     *
     * @param {!PreferenceStorage} newPrefs The new PreferenceStorage
     * @param {!string} oldID The id of the old PreferenceStorage
     * @param {?obj} defaults The defaults to add
     */
    function handleClientIdChange(newPrefs, oldID, defaults) {
        var oldPrefs = getPreferenceStorage(oldID);

        defaults = defaults || {};

        if (!newPrefs.getValue("newClientID")) {
            var data = oldPrefs.getAllValues();

            if ($.isEmptyObject(data)) {
                data = defaults;
            }

            newPrefs.setAllValues(data, false);
            newPrefs.setValue("newClientID", true);
        }
        delete prefStorage[oldID];
    }

    // Check localStorage for a preferencesKey. Production and unit test keys
    // are used to keep preferences separate within the same storage implementation.
    preferencesKey = localStorage.getItem("preferencesKey");

    if (!preferencesKey) {
        // use default key if none is found
        preferencesKey = PREFERENCES_CLIENT_ID;
        doLoadPreferences = true;
    } else {
        // using a non-default key, check for additional settings
        doLoadPreferences = !!(localStorage.getItem("doLoadPreferences"));
    }

    // Use localStorage by default
    _initStorage(localStorage);

    // Public API
    exports.getPreferenceStorage    = getPreferenceStorage;
    exports.savePreferences         = savePreferences;
    exports.handleClientIdChange    = handleClientIdChange;

    // Unit test use only
    exports._reset                  = _reset;
});<|endoftext|>


<commit_before>module.exports = Site;

var fs = require('fs'),
	path = require('path'),
	jade = require('jade'),
	express = require('express'),
	async = require('async'),
	parsedown = require('woods-parsedown'),
	settings = require('./settings');

var fsUtil = require('./util/fs.js'),
	Parsers = require('./Parsers'),
	Helpers = require('./Helpers'),
	Page = require('./Page'),
	Thumbnails = require('./Thumbnails');

require('util').inherits(Site, require('events').EventEmitter);

var loadSettings = function(site, callback) {
	fsUtil.readIfExists(site.getUri('settings.md'), function(err, data) {
		site.settings = err ? {} : parsedown(data);
		if (!site.settings.contentExtension)
			site.settings.contentExtension = settings.contentExtension;
		callback();
	});
};

function Site(woods, directory, watch, callback) {
	this.woods = woods;
	woods.site = this;
	this.directory = directory;
	this.parsers = new Parsers(this);
	this.helpers = new Helpers(this);
	this.thumbnails = new Thumbnails(this);
	if (watch)
		require('./watchDirectory')(this);
	installRoutes(this);
	var site = this;
	loadSettings(this, function() {
		site.parsers.load(function() {
			site.helpers.load(function() {
				site.build(callback);
			});
		});
	});
}

Site.prototype.getUri = function(file) {
	return path.resolve(this.directory, file || '');
};

Site.prototype._addType = function(type, callback) {
	if (this._types[type])
		return callback();

	// Check for templates belonging to type and install them
	var typeTemplates = this._types[type] = {},
		templateLocations = this._templateLocations[type] = {},
		templatesDir = getTemplateDirectory(this, type);

	var compileTemplate = function(file, doneCompiling) {
		// Compile jade templates:
		if ((/jade$/).test(file)) {
			var templateName = path.basename(file, '.jade');
			var location = templateLocations[templateName] =
					path.join(templatesDir, file);
			fs.readFile(location, 'utf-8', function(err, data) {
				if (!err)
					typeTemplates[templateName] = jade.compile(data, { filename: location });
				return doneCompiling(err);
			});
		} else {
			return doneCompiling();
		}
	};

	fsUtil.listOnlyVisibleFiles(templatesDir, function(err, files) {
		if (err || !files)
			return callback(err);
		async.each(files, compileTemplate, callback);
	});
};

// TODO: what happens if this function is called while
// the site is already being built?
Site.prototype.build = function(callback) {
	var site = this;
	site.pageCount = 0;
	// TODO: remove static routes
	site._types = {};
	site._templateLocations = {};
	site._addType('default', function(err) {
		if (err)
			return callback(err);
		site.root = new Page(site, null, '', null, function(err) {
			site.modified = Date.now();
			callback(err);
		});
	});
};

function getTemplateDirectory(site, type) {
	return site.getUri(path.join('templates', type || ''));
}

function escapeRegex(str) {
	return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}

function installRoutes(site) {
	site.woods.express.use(
		'/assets',
		express.static(site.getUri('assets'))
	);

	site.woods.express.get(/^(.*?)([0-9]*)*?$/, function(req, res, next) {
		var then = new Date(),
			page = site.root.get(req.params[0]);
		if (page) {
			res.end(page.template('html', {
				_activePage: page,
				request: req,
				query: req.query,
				number: req.params[1] && +req.params[1]
			}));
		} else {
			next();
		}
	});
}
<commit_msg>Undo unnecessary previous change.<commit_after>module.exports = Site;

var fs = require('fs'),
	path = require('path'),
	jade = require('jade'),
	express = require('express'),
	async = require('async'),
	parsedown = require('woods-parsedown'),
	settings = require('./settings');

var fsUtil = require('./util/fs.js'),
	Parsers = require('./Parsers'),
	Helpers = require('./Helpers'),
	watchDirectory = require('./watchDirectory'),
	Page = require('./Page'),
	Thumbnails = require('./Thumbnails');

require('util').inherits(Site, require('events').EventEmitter);

var loadSettings = function(site, callback) {
	fsUtil.readIfExists(site.getUri('settings.md'), function(err, data) {
		site.settings = err ? {} : parsedown(data);
		if (!site.settings.contentExtension)
			site.settings.contentExtension = settings.contentExtension;
		callback();
	});
};

function Site(woods, directory, watch, callback) {
	this.woods = woods;
	woods.site = this;
	this.directory = directory;
	this.parsers = new Parsers(this);
	this.helpers = new Helpers(this);
	this.thumbnails = new Thumbnails(this);
	if (watch)
		watchDirectory(this);
	installRoutes(this);
	var site = this;
	loadSettings(this, function() {
		site.parsers.load(function() {
			site.helpers.load(function() {
				site.build(callback);
			});
		});
	});
}

Site.prototype.getUri = function(file) {
	return path.resolve(this.directory, file || '');
};

Site.prototype._addType = function(type, callback) {
	if (this._types[type])
		return callback();

	// Check for templates belonging to type and install them
	var typeTemplates = this._types[type] = {},
		templateLocations = this._templateLocations[type] = {},
		templatesDir = getTemplateDirectory(this, type);

	var compileTemplate = function(file, doneCompiling) {
		// Compile jade templates:
		if ((/jade$/).test(file)) {
			var templateName = path.basename(file, '.jade');
			var location = templateLocations[templateName] =
					path.join(templatesDir, file);
			fs.readFile(location, 'utf-8', function(err, data) {
				if (!err)
					typeTemplates[templateName] = jade.compile(data, { filename: location });
				return doneCompiling(err);
			});
		} else {
			return doneCompiling();
		}
	};

	fsUtil.listOnlyVisibleFiles(templatesDir, function(err, files) {
		if (err || !files)
			return callback(err);
		async.each(files, compileTemplate, callback);
	});
};

// TODO: what happens if this function is called while
// the site is already being built?
Site.prototype.build = function(callback) {
	var site = this;
	site.pageCount = 0;
	// TODO: remove static routes
	site._types = {};
	site._templateLocations = {};
	site._addType('default', function(err) {
		if (err)
			return callback(err);
		site.root = new Page(site, null, '', null, function(err) {
			site.modified = Date.now();
			callback(err);
		});
	});
};

function getTemplateDirectory(site, type) {
	return site.getUri(path.join('templates', type || ''));
}

function escapeRegex(str) {
	return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}

function installRoutes(site) {
	site.woods.express.use(
		'/assets',
		express.static(site.getUri('assets'))
	);

	site.woods.express.get(/^(.*?)([0-9]*)*?$/, function(req, res, next) {
		var then = new Date(),
			page = site.root.get(req.params[0]);
		if (page) {
			res.end(page.template('html', {
				_activePage: page,
				request: req,
				query: req.query,
				number: req.params[1] && +req.params[1]
			}));
		} else {
			next();
		}
	});
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';

const fs = require('fs');
const path = require('path');
const axios = require('axios');
const iconv = require('iconv-lite');

// https://support.google.com/googleplay/android-developer/answer/6154891?hl=en
// https://support.google.com/googleplay/answer/1727131?hl=en

// On the CSV file, devices are ordered alphabetically (A-Z) by manufacturer name and listed in the following format:
//  Retail brand, marketing name, build.os.DEVICE, build.os.MODEL

const SUPPORTED_DEVICES_CSV = 'https://storage.googleapis.com/play_public/supported_devices.csv';

const DEVICES_OUTPUT_FILE = path.join(__dirname, 'devices.json');
const BRANDS_OUTPUT_FILE = path.join(__dirname, 'brands.json');

const CVS_SEPARATOR = ',';
const CVS_QUOTE = '"';
const CVS_ESCAPE = '"';
const CVS_NEWLINE = '\r\n';

const CVS_SEPARATOR_CODE = new Buffer(CVS_SEPARATOR)[0];
const CVS_QUOTE_CODE = new Buffer(CVS_QUOTE)[0];
const CVS_ESCAPE_CODE = new Buffer(CVS_ESCAPE)[0];

function getCvs() {
  console.log('Downloading: ' + SUPPORTED_DEVICES_CSV);

  axios.get(SUPPORTED_DEVICES_CSV)
    .then(buildJSON)
    .catch(e => {
      console.log('Download failed');
      console.log(e);
    });
}

// convert utf-16le to utf8
function decodeRaw(data) {
  // check file encoding:
  // $ file -I supported_devices.csv
  // supported_devices.csv: text/plain; charset=utf-16le

  let buffer = new Buffer(data, 'binary');
  return iconv.decode(buffer, 'utf-16le');
}

function buildJSON(response) {

//  console.log(response.data);
//  console.log(response.status);
//  console.log(response.statusText);
//  console.log(response.headers);
//  console.log(response.config);

  console.log('Downloaded', response.status, response.statusText);
  console.log('File size: ' + response.headers['content-length'] + ' bytes');

  let devices = parseCVS(decodeRaw(response.data));

  // remove first row: "Retail Branding,Marketing Name,Device,Model"
  devices.shift();

  console.log(devices.length + ' devices');

  fs.writeFile(DEVICES_OUTPUT_FILE, JSON.stringify(devices, null, 2), (err) => {
    if (err) throw err;
    console.log('Device list saved to ' + DEVICES_OUTPUT_FILE);
  });

  let brands = [];
  devices.forEach(device => {
    if (!device.brand) {
      return;
    }
    if (brands.indexOf(device.brand) === -1) {
      brands.push(device.brand);
    }
  });

  console.log(brands.length + ' brands');

  fs.writeFile(BRANDS_OUTPUT_FILE, JSON.stringify(brands, null, 2), (err) => {
    if (err) throw err;
    console.log('Brand list saved to ' + BRANDS_OUTPUT_FILE);
  });

}

function parseCVS(data) {
  let dataArr = data.split(CVS_NEWLINE);
  let out = [];

  dataArr.map(item => {
    let parts = splitRow(item);
    if (parts) {
      out.push({
        brand: parts[0],
        name: parts[1],
        device: parts[2],
        model: parts[3]
      });
    }
  });

  return out;
}

function splitRow(row) {
  let parts;
  if ((row.indexOf(CVS_QUOTE) > -1) || (row.indexOf(CVS_ESCAPE) > -1)) {
    parts = splitSpecial(row);
  } else {
    parts = row.split(CVS_SEPARATOR);
  }
  if (row.trim().length === 0) {
    // empty row
    return;
  }
  if (parts.length !== 4) {
    console.log('Invalid row:', row, row.length, parts);
    return;
  }
  return parts;
}

function splitSpecial(data) {
  if (typeof data === 'string') data = new Buffer(data);

  let start = 0;
  let end = data.length;
  var cells = [];
  var isQuoted = false;
  var offset = start;

  for (var i = start; i < end; i++) {
    var isStartingQuote = !isQuoted && data[i] === CVS_QUOTE_CODE;
    var isEndingQuote = isQuoted && data[i] === CVS_QUOTE_CODE && i + 1 <= end && data[i + 1] === CVS_SEPARATOR_CODE;
    var isEscape = isQuoted && data[i] === CVS_ESCAPE_CODE && i + 1 < end && data[i + 1] === CVS_QUOTE_CODE;

    if (isStartingQuote || isEndingQuote) {
      isQuoted = !isQuoted;
      continue;
    } else if (isEscape) {
      i++;
      continue;
    }

    if (data[i] === CVS_SEPARATOR_CODE && !isQuoted) {
      cells.push(cell(data, offset, i));
      offset = i + 1;
    }
  }

  if (offset < end) cells.push(cell(data, offset, end));
  if (data[end - 1] === CVS_SEPARATOR_CODE) cells.push('');

  return cells;
}

function cell(data, start, end) {
  // remove quotes from quoted cells
  let quotes = 0;

  if (data[start] === CVS_QUOTE_CODE && data[end - 1] === CVS_QUOTE_CODE) {
    start++;
    end--;
    quotes = 1;
  }

  let i = start;
  let y = start;
  for (; i < end; i++) {
    // check for escape characters and skip them
    if (data[i] === CVS_ESCAPE_CODE && i + 1 < end && data[i + 1] === CVS_QUOTE_CODE) i++;
    if (y !== i) data[y] = data[i];
    y++;
  }

  return data.toString('utf-8', start, end - quotes);
}

// start
getCvs();
<commit_msg>Use let<commit_after>#!/usr/bin/env node

'use strict';

const fs = require('fs');
const path = require('path');
const axios = require('axios');
const iconv = require('iconv-lite');

// https://support.google.com/googleplay/android-developer/answer/6154891?hl=en
// https://support.google.com/googleplay/answer/1727131?hl=en

// On the CSV file, devices are ordered alphabetically (A-Z) by manufacturer name and listed in the following format:
//  Retail brand, marketing name, build.os.DEVICE, build.os.MODEL

const SUPPORTED_DEVICES_CSV = 'https://storage.googleapis.com/play_public/supported_devices.csv';

const DEVICES_OUTPUT_FILE = path.join(__dirname, 'devices.json');
const BRANDS_OUTPUT_FILE = path.join(__dirname, 'brands.json');

const CVS_SEPARATOR = ',';
const CVS_QUOTE = '"';
const CVS_ESCAPE = '"';
const CVS_NEWLINE = '\r\n';

const CVS_SEPARATOR_CODE = new Buffer(CVS_SEPARATOR)[0];
const CVS_QUOTE_CODE = new Buffer(CVS_QUOTE)[0];
const CVS_ESCAPE_CODE = new Buffer(CVS_ESCAPE)[0];

function getCvs() {
  console.log('Downloading: ' + SUPPORTED_DEVICES_CSV);

  axios.get(SUPPORTED_DEVICES_CSV)
    .then(buildJSON)
    .catch(e => {
      console.log('Download failed');
      console.log(e);
    });
}

// convert utf-16le to utf8
function decodeRaw(data) {
  // check file encoding:
  // $ file -I supported_devices.csv
  // supported_devices.csv: text/plain; charset=utf-16le

  let buffer = new Buffer(data, 'binary');
  return iconv.decode(buffer, 'utf-16le');
}

function buildJSON(response) {

//  console.log(response.data);
//  console.log(response.status);
//  console.log(response.statusText);
//  console.log(response.headers);
//  console.log(response.config);

  console.log('Downloaded', response.status, response.statusText);
  console.log('File size: ' + response.headers['content-length'] + ' bytes');

  let devices = parseCVS(decodeRaw(response.data));

  // remove first row: "Retail Branding,Marketing Name,Device,Model"
  devices.shift();

  console.log(devices.length + ' devices');

  fs.writeFile(DEVICES_OUTPUT_FILE, JSON.stringify(devices, null, 2), (err) => {
    if (err) throw err;
    console.log('Device list saved to ' + DEVICES_OUTPUT_FILE);
  });

  let brands = [];
  devices.forEach(device => {
    if (!device.brand) {
      return;
    }
    if (brands.indexOf(device.brand) === -1) {
      brands.push(device.brand);
    }
  });

  console.log(brands.length + ' brands');

  fs.writeFile(BRANDS_OUTPUT_FILE, JSON.stringify(brands, null, 2), (err) => {
    if (err) throw err;
    console.log('Brand list saved to ' + BRANDS_OUTPUT_FILE);
  });

}

function parseCVS(data) {
  let dataArr = data.split(CVS_NEWLINE);
  let out = [];

  dataArr.map(item => {
    let parts = splitRow(item);
    if (parts) {
      out.push({
        brand: parts[0],
        name: parts[1],
        device: parts[2],
        model: parts[3]
      });
    }
  });

  return out;
}

function splitRow(row) {
  let parts;
  if ((row.indexOf(CVS_QUOTE) > -1) || (row.indexOf(CVS_ESCAPE) > -1)) {
    parts = splitSpecial(row);
  } else {
    parts = row.split(CVS_SEPARATOR);
  }
  if (row.trim().length === 0) {
    // empty row
    return;
  }
  if (parts.length !== 4) {
    console.log('Invalid row:', row, row.length, parts);
    return;
  }
  return parts;
}

function splitSpecial(data) {
  if (typeof data === 'string') data = new Buffer(data);

  let start = 0;
  let end = data.length;
  let cells = [];
  let isQuoted = false;
  let offset = start;

  for (let i = start; i < end; i++) {
    let isStartingQuote = !isQuoted && data[i] === CVS_QUOTE_CODE;
    let isEndingQuote = isQuoted && data[i] === CVS_QUOTE_CODE && i + 1 <= end && data[i + 1] === CVS_SEPARATOR_CODE;
    let isEscape = isQuoted && data[i] === CVS_ESCAPE_CODE && i + 1 < end && data[i + 1] === CVS_QUOTE_CODE;

    if (isStartingQuote || isEndingQuote) {
      isQuoted = !isQuoted;
      continue;
    } else if (isEscape) {
      i++;
      continue;
    }

    if (data[i] === CVS_SEPARATOR_CODE && !isQuoted) {
      cells.push(cell(data, offset, i));
      offset = i + 1;
    }
  }

  if (offset < end) cells.push(cell(data, offset, end));
  if (data[end - 1] === CVS_SEPARATOR_CODE) cells.push('');

  return cells;
}

function cell(data, start, end) {
  // remove quotes from quoted cells
  let quotes = 0;

  if (data[start] === CVS_QUOTE_CODE && data[end - 1] === CVS_QUOTE_CODE) {
    start++;
    end--;
    quotes = 1;
  }

  let i = start;
  let y = start;
  for (; i < end; i++) {
    // check for escape characters and skip them
    if (data[i] === CVS_ESCAPE_CODE && i + 1 < end && data[i + 1] === CVS_QUOTE_CODE) i++;
    if (y !== i) data[y] = data[i];
    y++;
  }

  return data.toString('utf-8', start, end - quotes);
}

// start
getCvs();
<|endoftext|>


<commit_before>"use strict";
angular.module('myApp.login', ['firebase.utils', 'firebase.auth', 'ngRoute'])

    .config(['$routeProvider', function($routeProvider) {
      $routeProvider.when('/login', {
        controller: 'LoginCtrl',
        templateUrl: 'login/login.html'
      });
    }])

    .controller('LoginCtrl', ['$scope', 'Auth', '$location', 'fbutil', '$firebaseObject', function($scope, Auth, $location, fbutil, $firebaseObject) {
      $scope.email = null;
      $scope.pass = null;

      $scope.login = function(email, pass) {
        Auth.$authWithOAuthPopup('google', {scope:'email'})
            .then(function (authObject) {
              console.log(authObject);
              var ref = fbutil.ref('users', authObject.uid);
              return fbutil.handler(function(cb) {
                ref.set({email: authObject.google.email, name: authObject.google.cachedUserProfile.name, online: 'true'}, cb);
              });
            })
            .then(function(/* user */) {
              // redirect to the account page
              var authdata = Auth.$getAuth();
              console.log('Login UID = '+authdata.uid);
              $location.path('/account');
            }, function(err) {
              $scope.err = errMessage(err);
            });
      };
    }]);<commit_msg>no message<commit_after>"use strict";
angular.module('myApp.login', ['firebase.utils', 'firebase.auth', 'ngRoute'])

    .config(['$routeProvider', function($routeProvider) {
      $routeProvider.when('/login', {
        controller: 'LoginCtrl',
        templateUrl: 'login/login.html'
      });
    }])

    .controller('LoginCtrl', ['$scope', 'Auth', '$location', 'fbutil', '$firebaseObject', function($scope, Auth, $location, fbutil, $firebaseObject) {
      $scope.email = null;
      $scope.pass = null;

      $scope.login = function(email, pass) {
        Auth.$authWithOAuthPopup('google', {scope:'email'})
            .then(function (authObject) {
              console.log(authObject);
                var profile = $firebaseObject(fbutil.ref('users', authObject.uid));
              var ref = fbutil.ref('users', authObject.uid);

                var obj = $firebaseObject(ref);

                // to take an action after the data loads, use the $loaded() promise
                obj.$loaded().then(function() {
                    console.log("loaded record:", obj.$id, obj.someOtherKeyInData);

                    // To iterate the key/value pairs of the object, use angular.forEach()
                    angular.forEach(obj, function(value, key) {
                        console.log(key, value);
                    });
                });
              return fbutil.handler(function(cb) {
                ref.set({email: authObject.google.email, name: authObject.google.cachedUserProfile.name, online: 'true'}, cb);
              });
            })
            .then(function(/* user */) {
              // redirect to the account page
              var authdata = Auth.$getAuth();
              console.log('Login UID = '+authdata.uid);
              $location.path('/account');
            }, function(err) {
              $scope.err = errMessage(err);
            });
      };
    }]);<|endoftext|>


<commit_before>var debug           = require('debug')('connman-simplified:wifi');
var async           = require('async');
var util            = require("util");
var Base            = require('./Base');
var ms              = require('ms');
var configFiles     = require('./ConfigFiles.js');
var Parser          = require('./Parser');

var _super = Base.prototype;

var _timeoutWiFiEnable = 3000;
var _numGetServiceAttempts = 5;
var _getServiceAttemptTimeout = 1000;
var _numGetServicesAttempts = _numGetServiceAttempts;
var _getServicesAttemptTimeout = _getServiceAttemptTimeout;
var _servicesCache = []; // cache of services, use while tethering

/** https://kernel.googlesource.com/pub/scm/network/connman/connman/+/1.14/doc/service-api.txt
 *  string State [readonly]
 *     The service state information.
 *     Valid states are "idle", "failure", "association", "configuration", "ready", "disconnect" and "online".
 */
var STATES = {
  IDLE: 'idle',
  FAILURE: 'failure',
  ASSOCIATION: 'association',
  CONFIGURATION: 'configuration',
  READY: 'ready',
  DISCONNECT: 'disconnect',
  ONLINE: 'online',
};

module.exports = WiFi;
module.exports.STATES = STATES;

function WiFi(connman) {
  Base.call(this);
  this.connman = connman;
}

util.inherits(WiFi, Base);

WiFi.prototype.init = function(callback) {
  //debug("init");
  var self = this;
  // Retrieve WiFi technology
  // https://kernel.googlesource.com/pub/scm/network/connman/connman/+/1.14/doc/technology-api.txt
  var tech = self.connman.technologies.WiFi;
  if(tech === undefined) {
    if(callback) callback(new Error("No WiFi hardware available"));
    return;
  }
  _super.init.call(self,tech,function(err,properties) {
    if(properties.powered) { // already powered?
      if(callback) callback(err,properties);
    } else {
      self.enable(function(err) {
        if(callback) callback(err,properties);
      });
    }
  });
  self.on('services',onServices);
};
WiFi.prototype.enable = function(callback) {
  this.setProperty('Powered', true, function(err) {
    // Sometimes this failes, our hypothesis is that
    // this is usually caused by a shortage of power
    if(err) {
      debug('[Error] Enabling wifi failed: ',err);
    }
    // delay, probably because of: https://01.org/jira/browse/CM-644
    setTimeout(callback, _timeoutWiFiEnable, err);
  });
};
WiFi.prototype.disable = function(callback) {
  this.setProperty('Powered', false, callback);
};

/* Get available networks
 * goal of this method is to return a good amount of networks
 * therefore there is a attempts and timeout system build in
 */
WiFi.prototype.getNetworks = function(callback) {
  var self = this;
  var attempt = 0;

  self.scan(); // start scan, but don't wait for it
  setTimeout(function() { // wait a moment before retrieving services
    async.retry(_numGetServicesAttempts, function(nextRetry) {
      debug('search services attempt: ',++attempt,'/',_numGetServicesAttempts);
      self.iface.getServices(function(err,services) {
        if(!err && Object.keys(services).length === 0) {
          err = new Error('No WiFi networks found');
        }
        if(err) {
          debug('getServices err: ',err);
          self.scan(); // start scan, but don't wait for it
          return setTimeout(nextRetry, _getServicesAttemptTimeout, err); // try again
        }
        self._setServices(Parser.parseServices(services));
        var servicesArr = self._obj2Arr(self.services);
        callback(null, servicesArr);
      });
    },callback);
  },_getServicesAttemptTimeout);
};
WiFi.prototype.getNetworksCache = function(callback) {
  debug("getNetworksCache");
  var servicesArr = this._obj2Arr(_servicesCache);
  callback(null, servicesArr);
};
WiFi.prototype.scan = function(switchTethering,callback) {
  var self = this;
  if(typeof switchTethering == 'function') {
    callback = switchTethering;
    switchTethering = false;
  }
  debug("scan "+(switchTethering? '& switchTethering' : ''));

  if(self.properties.tethering && !switchTethering) {
    debug("[Warning] Scanning while in tethering mode is usually not supported");
  }

  // Because our hardware can't scan and tether at the same time we
  // might need to switch off tethering, scan and start tethering again
  // ToDo: research wheter it's possible to keep the hotspot clients connected
  if(self.properties.tethering && switchTethering) {
    var startTime = Date.now();
    self.closeHotspot(function(err) {
      self.iface.scan(function() { // ToDo: add retries?
        //logNetworks();
        self.openHotspot(null,null,function(err) {
          debug('switchTethering time: ',ms(Date.now()-startTime));
          if(callback) callback(err);
        });
      });
    });
  } else {
    self.iface.scan(function(err) {
      if(err) {
        debug("[Error] scanning: ",err); // ToDo: remove?
        if(err.message == 'org.freedesktop.DBus.Error.NoReply') {
          debug("[Error] Scan failed, probably because I'm a hotspot / tethering");
        }
      }
      if(callback) callback(err);
    });
  }
};
WiFi.prototype.join = function(ssid,passphrase,callback) {
  var self = this;
  debug("join: ",ssid);
  if(ssid === undefined) {
    if(callback) callback(new Error("ssid is required"));
    return;
  }
  if(typeof passphrase == 'function') {
    callback = passphrase;
    passphrase = '';
  }
  var targetService;
  var targetServiceProperties;
  async.series([
    // close hotspot
    self.closeHotspot.bind(self),
    // find service / network
    function(next) {
      getServiceBySSID.call(self,ssid,function(err,service,properties) {
        if(err) return next(err);
        targetService = service;
        targetServiceProperties = properties;
        next();
      });
    },
    // check current state
    function(next) {
      var connected = (targetServiceProperties.state == STATES.READY ||
                       targetServiceProperties.state == STATES.READY);
      if(connected) next(new Error('Already connected'));
      else next();
    },
    // handle security
    function(next) {
      var secured = targetServiceProperties.security.indexOf('none') === -1;
      if(!secured) return next(); // no security
      if(!passphrase || passphrase === '') {
        if(targetServiceProperties.favorite) next();
        else next(new Error("No passphrase supplied for secured network"));
      } else {
        configFiles.create(ssid,passphrase,next);
      }
    },
    // switch to this service
    function(next) {
      self._setService(targetService.name,targetServiceProperties);
      next();
    },
    // connect to service
    function(next) {
      targetService.connect(function(err, newAgent) {
        debug("connect response: ",err || ''/*,newAgent*/);
        next(err);
      });
    },
    // listen to state
    function(next) {
      function onChange(type, value) {
        if(type !== 'State') return;
        //debug("service State: ",value);
        switch(value) {
          // when wifi ready and online
          case STATES.READY:
          case STATES.ONLINE:
            targetService.removeListener('PropertyChanged',onChange);
            next();
            break;
          case STATES.FAILURE:
            var err = new Error("Joining network failed (wrong password?)");
            targetService.removeListener('PropertyChanged',onChange);
            next(err);
            // ToDo include error... (sometimes there is a Error property change, with a value like 'invalid-key')
            break;
        }
      }
      targetService.on('PropertyChanged',onChange);
    }
  ],function(err) {
    debug('join finished: ',err || '');
    if(callback) callback(err);
  });
};
WiFi.prototype.joinFavorite = function(callback) {
  debug("joinFavorite");
  var self = this;
  var favoriteSSID;
  async.waterfall([
    // close hotspot
    self.closeHotspot.bind(self),

    // find favorite network
    getFavoriteService.bind(self),
    // join favorite network
    function(service,properties,next) {
      self.join(properties.ssid,next);
    }
  ], function(err) {
    debug('joinFavorite series finished: ',err || '');
    if(callback) callback(err);
  });
};
WiFi.prototype.disconnect = function(callback) {
  debug("disconnect");
  if (!this.service) {
    if (callback) callback(new Error('no service to disconnect from'));
    return;
  }
  this.service.disconnect(function(err) {
    if(callback) callback(err);
  });
};
WiFi.prototype.forgetNetwork = function(ssid,callback) {
  //ssid parameter is optional: grab callback and optional ssid
  var args = [];
  for (var i = 0; i < arguments.length; i++) {
    args.push(arguments[i]);
  }
  callback = args.pop();
  ssid = args.shift() || '';

  if (ssid !== '') {
    debug('forgetNetwork: ',ssid);
    getServiceBySSID.call(this,ssid,function(err, service) {
      if (err) {
        if (callback) callback(err);
        return;
      }
      if (service) service.remove();
    });
    configFiles.remove(ssid,callback);
  } else {
    debug('forget current network:' + this.serviceProperties.ssid);
    if (this.service) {
      this.service.remove();
      configFiles.remove(this.serviceProperties.ssid, callback);
    } else {
      if (callback) callback(new Error('no current service'));
    }
  }
};
WiFi.prototype.closeHotspot = function(callback) {
  debug("closeHotspot");
  var self = this;
  // Having changing the Tethering property doesn't mean the hotspot is closed.
  // A better indicator is listening to Tethering and Powered property changes
  // The Tethering changes to false, Powered is set to true (maybe the device restarts?)
  // But the best indicator seems to wait for the available services to change.
  function onChange(changes,removed) {
    if(callback) callback();
    self.removeListener('servicesChanged',onChange);
  }
  self.on('servicesChanged',onChange);

  self.iface.disableTethering(function(err, res) {
    //debug("disableTethering response: ",err,res);
    if (err) {
      // not reporting already disabled as error
      if (err.message === 'net.connman.Error.AlreadyDisabled') {
        debug('[NOTE] Hotspot already closed');
        err = null;
      }
      self.removeListener('servicesChanged',onChange);
      if (callback) callback(err);
      return;
    }
  });
};
WiFi.prototype.openHotspot = function(ssid,passphrase,callback) {
  debug("openHotspot");
  var self = this;
  // changing ssid or passphrase works while already hotspot requires disable first
  // see: https://01.org/jira/browse/CM-668
  var args = arguments;
  if(self.properties.tethering) {
    self.closeHotspot(function() {
      self.iface.enableTethering.apply(self.iface,args);
    });
  } else {
    self.iface.enableTethering.apply(self.iface,args);
  }
};

/********************
 * Event handlers
 ********************/
function onServices() {
  if(!this.properties.tethering) {
    //debug('update servicesCache');
    _servicesCache = this.services;
  }
}

/********************
 * Private functions
 ********************/
function getServiceBySSID(ssid,callback) {
  searchService.call(this,{Name:ssid},callback);
}
function getFavoriteService(callback) {
  searchService.call(this,{Favorite:true},callback);
}
function searchService(query,numRetries,callback) {
  //debug('searchService query: ',query);
  if(typeof numRetries == 'function') {
    callback = numRetries;
    numRetries = _numGetServiceAttempts;
  }
  var self = this;
  var attempt = 0;
  async.retry(numRetries, function(nextRetry) {
    attempt++;
    debug('search service attempt: ',attempt,'/',numRetries);
    self.scan(); // start scan, but don't wait for it
    self.iface.searchService(query,function(err,service,properties) {
      if(err) setTimeout(nextRetry, _getServiceAttemptTimeout, err);
      else callback(err, service, Parser.parseService(properties));
    });
  },callback);
}

//function logStatus() {
//  var techProps = _techProperties;
//  var serviceProps = _serviceProperties;
//  if(serviceProps && serviceProps.state){
//    var connectionStatus = 'connection status: ';
//    connectionStatus += (techProps.connected)? "Connected" : "Disconnected";
//    connectionStatus += " "+serviceProps.state;
//    connectionStatus += " '"+serviceProps.ssid+"'";
//    connectionStatus += " "+serviceProps.security;
//    connectionStatus += " "+serviceProps.ipaddress;
//    debug(connectionStatus);
//  }
//  if(techProps && techProps.tethering) {
//    debug('tethering: ',techProps.tetheringIdentifier,techProps.tetheringPassphrase);
//  }
//}
<commit_msg>improve error checking on forgetNetwork (optional ssid) and solve eslint typo warnings<commit_after>var debug           = require('debug')('connman-simplified:wifi');
var async           = require('async');
var util            = require("util");
var Base            = require('./Base');
var ms              = require('ms');
var configFiles     = require('./ConfigFiles.js');
var Parser          = require('./Parser');

var _super = Base.prototype;

var _timeoutWiFiEnable = 3000;
var _numGetServiceAttempts = 5;
var _getServiceAttemptTimeout = 1000;
var _numGetServicesAttempts = _numGetServiceAttempts;
var _getServicesAttemptTimeout = _getServiceAttemptTimeout;
var _servicesCache = []; // cache of services, use while tethering

/** https://kernel.googlesource.com/pub/scm/network/connman/connman/+/1.14/doc/service-api.txt
 *  string State [readonly]
 *     The service state information.
 *     Valid states are "idle", "failure", "association", "configuration", "ready", "disconnect" and "online".
 */
var STATES = {
  IDLE: 'idle',
  FAILURE: 'failure',
  ASSOCIATION: 'association',
  CONFIGURATION: 'configuration',
  READY: 'ready',
  DISCONNECT: 'disconnect',
  ONLINE: 'online',
};

module.exports = WiFi;
module.exports.STATES = STATES;

function WiFi(connman) {
  Base.call(this);
  this.connman = connman;
}

util.inherits(WiFi, Base);

WiFi.prototype.init = function(callback) {
  //debug("init");
  var self = this;
  // Retrieve WiFi technology
  // https://kernel.googlesource.com/pub/scm/network/connman/connman/+/1.14/doc/technology-api.txt
  var tech = self.connman.technologies.WiFi;
  if (tech === undefined) {
    if (callback) callback(new Error('No WiFi hardware available'));
    return;
  }
  _super.init.call(self,tech,function(err, properties) {
    if (properties.powered) { // already powered?
      if (callback) callback(err,properties);
    } else {
      self.enable(function(err) {
        if (callback) callback(err,properties);
      });
    }
  });
  self.on('services',onServices);
};
WiFi.prototype.enable = function(callback) {
  this.setProperty('Powered', true, function(err) {
    // Sometimes this failes, our hypothesis is that
    // this is usually caused by a shortage of power
    if (err) {
      debug('[Error] Enabling wifi failed: ',err);
    }
    // delay, probably because of: https://01.org/jira/browse/CM-644
    setTimeout(callback, _timeoutWiFiEnable, err);
  });
};
WiFi.prototype.disable = function(callback) {
  this.setProperty('Powered', false, callback);
};

/* Get available networks
 * goal of this method is to return a good amount of networks
 * therefore there is a attempts and timeout system build in
 */
WiFi.prototype.getNetworks = function(callback) {
  var self = this;
  var attempt = 0;

  self.scan(); // start scan, but don't wait for it
  setTimeout(function() { // wait a moment before retrieving services
    async.retry(_numGetServicesAttempts, function(nextRetry) {
      debug('search services attempt: ',++attempt,'/',_numGetServicesAttempts);
      self.iface.getServices(function(err, services) {
        if (!err && Object.keys(services).length === 0) {
          err = new Error('No WiFi networks found');
        }
        if (err) {
          debug('getServices err: ',err);
          self.scan(); // start scan, but don't wait for it
          return setTimeout(nextRetry, _getServicesAttemptTimeout, err); // try again
        }
        self._setServices(Parser.parseServices(services));
        var servicesArr = self._obj2Arr(self.services);
        callback(null, servicesArr);
      });
    },callback);
  },_getServicesAttemptTimeout);
};
WiFi.prototype.getNetworksCache = function(callback) {
  debug('getNetworksCache');
  var servicesArr = this._obj2Arr(_servicesCache);
  callback(null, servicesArr);
};
WiFi.prototype.scan = function(switchTethering,callback) {
  var self = this;
  if (typeof switchTethering === 'function') {
    callback = switchTethering;
    switchTethering = false;
  }
  debug('scan ' + (switchTethering ? '& switchTethering' : ''));

  if (self.properties.tethering && !switchTethering) {
    debug('[Warning] Scanning while in tethering mode is usually not supported');
  }

  // Because our hardware can't scan and tether at the same time we
  // might need to switch off tethering, scan and start tethering again
  // ToDo: research wheter it's possible to keep the hotspot clients connected
  if (self.properties.tethering && switchTethering) {
    var startTime = Date.now();
    self.closeHotspot(function(err) {
      self.iface.scan(function() { // ToDo: add retries?
        //logNetworks();
        self.openHotspot(null,null,function(err) {
          debug('switchTethering time: ',ms(Date.now() - startTime));
          if (callback) callback(err);
        });
      });
    });
  } else {
    self.iface.scan(function(err) {
      if (err) {
        debug('[Error] scanning: ',err); // ToDo: remove?
        if (err.message === 'org.freedesktop.DBus.Error.NoReply') {
          debug("[Error] Scan failed, probably because I'm a hotspot / tethering");
        }
      }
      if (callback) callback(err);
    });
  }
};
WiFi.prototype.join = function(ssid,passphrase,callback) {
  var self = this;
  debug('join: ',ssid);
  if (ssid === undefined) {
    if (callback) callback(new Error('ssid is required'));
    return;
  }
  if (typeof passphrase === 'function') {
    callback = passphrase;
    passphrase = '';
  }
  var targetService;
  var targetServiceProperties;
  async.series([
    // close hotspot
    self.closeHotspot.bind(self),
    // find service / network
    function(next) {
      getServiceBySSID.call(self,ssid,function(err,service,properties) {
        if (err) return next(err);
        targetService = service;
        targetServiceProperties = properties;
        next();
      });
    },
    // check current state
    function(next) {
      var connected = (targetServiceProperties.state == STATES.READY ||
                       targetServiceProperties.state == STATES.READY);
      if (connected) next(new Error('Already connected'));
      else next();
    },
    // handle security
    function(next) {
      var secured = targetServiceProperties.security.indexOf('none') === -1;
      if (!secured) return next(); // no security
      if (!passphrase || passphrase === '') {
        if (targetServiceProperties.favorite) next();
        else next(new Error('No passphrase supplied for secured network'));
      } else {
        configFiles.create(ssid,passphrase,next);
      }
    },
    // switch to this service
    function(next) {
      self._setService(targetService.name,targetServiceProperties);
      next();
    },
    // connect to service
    function(next) {
      targetService.connect(function(err, newAgent) {
        debug('connect response: ',err || ''/*,newAgent*/);
        next(err);
      });
    },
    // listen to state
    function(next) {
      function onChange(type, value) {
        if (type !== 'State') return;
        //debug("service State: ",value);
        switch (value) {
          // when wifi ready and online
          case STATES.READY:
          case STATES.ONLINE:
            targetService.removeListener('PropertyChanged',onChange);
            next();
            break;
          case STATES.FAILURE:
            var err = new Error('Joining network failed (wrong password?)');
            targetService.removeListener('PropertyChanged',onChange);
            next(err);
            // ToDo include error... (sometimes there is a Error property change, with a value like 'invalid-key')
            break;
        }
      }
      targetService.on('PropertyChanged', onChange);
    }
  ],function(err) {
    debug('join finished: ',err || '');
    if (callback) callback(err);
  });
};
WiFi.prototype.joinFavorite = function(callback) {
  debug('joinFavorite');
  var self = this;
  var favoriteSSID;
  async.waterfall([
    // close hotspot
    self.closeHotspot.bind(self),

    // find favorite network
    getFavoriteService.bind(self),
    // join favorite network
    function(service,properties,next) {
      self.join(properties.ssid,next);
    }
  ], function(err) {
    debug('joinFavorite series finished: ',err || '');
    if (callback) callback(err);
  });
};
WiFi.prototype.disconnect = function(callback) {
  debug('disconnect');
  if (!this.service) {
    if (callback) callback(new Error('no service to disconnect from'));
    return;
  }
  this.service.disconnect(function(err) {
    if (callback) callback(err);
  });
};
WiFi.prototype.forgetNetwork = function(ssid,callback) {
  //ssid parameter is optional, might be callback function
  if (typeof ssid === 'function') {
    callback = ssid;
    debug('forget current network:' + this.serviceProperties.ssid);
    if (this.service) {
      this.service.remove();
      configFiles.remove(this.serviceProperties.ssid, callback);
      if (callback) callback();
    } else {
      if (callback) callback(new Error('no current service'));
    }
  } else {
    if (typeof ssid !== 'string') {
      if (callback) callback(new Error('provided ssid is not a string'));
      return;
    }
    debug('forgetNetwork: ',ssid);
    getServiceBySSID.call(this,ssid,function(err, service) {
      if (err) {
        if (callback) callback(err);
        return;
      }
      if (service) service.remove();
    });
    configFiles.remove(ssid,callback);
  }
};
WiFi.prototype.closeHotspot = function(callback) {
  debug('closeHotspot');
  var self = this;
  // Having changing the Tethering property doesn't mean the hotspot is closed.
  // A better indicator is listening to Tethering and Powered property changes
  // The Tethering changes to false, Powered is set to true (maybe the device restarts?)
  // But the best indicator seems to wait for the available services to change.
  function onChange(changes, removed) {
    if (callback) callback();
    self.removeListener('servicesChanged',onChange);
  }
  self.on('servicesChanged',onChange);

  self.iface.disableTethering(function(err, res) {
    //debug("disableTethering response: ",err,res);
    if (err) {
      // not reporting already disabled as error
      if (err.message === 'net.connman.Error.AlreadyDisabled') {
        debug('[NOTE] Hotspot already closed');
        err = null;
      }
      self.removeListener('servicesChanged',onChange);
      if (callback) callback(err);
      return;
    }
  });
};
WiFi.prototype.openHotspot = function(ssid,passphrase,callback) {
  debug('openHotspot');
  var self = this;
  // changing ssid or passphrase works while already hotspot requires disable first
  // see: https://01.org/jira/browse/CM-668
  var args = arguments;
  if (self.properties.tethering) {
    self.closeHotspot(function() {
      self.iface.enableTethering.apply(self.iface,args);
    });
  } else {
    self.iface.enableTethering.apply(self.iface,args);
  }
};

/********************
 * Event handlers
 ********************/
function onServices() {
  if (!this.properties.tethering) {
    //debug('update servicesCache');
    _servicesCache = this.services;
  }
}

/********************
 * Private functions
 ********************/
function getServiceBySSID(ssid,callback) {
  searchService.call(this, {Name: ssid}, callback);
}
function getFavoriteService(callback) {
  searchService.call(this, {Favorite: true}, callback);
}
function searchService(query, numRetries, callback) {
  //debug('searchService query: ',query);
  if (typeof numRetries === 'function') {
    callback = numRetries;
    numRetries = _numGetServiceAttempts;
  }
  var self = this;
  var attempt = 0;
  async.retry(numRetries, function(nextRetry) {
    attempt++;
    debug('search service attempt: ',attempt,'/',numRetries);
    self.scan(); // start scan, but don't wait for it
    self.iface.searchService(query,function(err, service, properties) {
      if (err) setTimeout(nextRetry, _getServiceAttemptTimeout, err);
      else callback(err, service, Parser.parseService(properties));
    });
  },callback);
}

//function logStatus() {
//  var techProps = _techProperties;
//  var serviceProps = _serviceProperties;
//  if(serviceProps && serviceProps.state){
//    var connectionStatus = 'connection status: ';
//    connectionStatus += (techProps.connected)? "Connected" : "Disconnected";
//    connectionStatus += " "+serviceProps.state;
//    connectionStatus += " '"+serviceProps.ssid+"'";
//    connectionStatus += " "+serviceProps.security;
//    connectionStatus += " "+serviceProps.ipaddress;
//    debug(connectionStatus);
//  }
//  if(techProps && techProps.tethering) {
//    debug('tethering: ',techProps.tetheringIdentifier,techProps.tetheringPassphrase);
//  }
//}
<|endoftext|>


<commit_before>import Node from '../Node.js';
import reserved from '../../utils/reserved.js';
import { UNKNOWN } from '../../utils/sentinels.js';
import stringify from '../../utils/stringify.js';

function isValidIdentifier ( str ) {
	// TODO there's probably a bit more to it than this
	return !reserved[ str ] && /^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test( str );
}

function canFold ( node, parent ) {
	while ( parent.type === 'ParenthesizedExpression' ) {
		node = parent;
		parent = node.parent;
	}

	if ( parent.type === 'UpdateExpression' ) return false;
	if ( parent.type === 'AssignmentExpression' ) return node !== parent.left;

	return true;
}

export default class MemberExpression extends Node {
	getLeftHandSide () {
		return this.object.getLeftHandSide();
	}

	getValue () {
		const objectValue = this.object.getValue();
		if ( !objectValue || objectValue === UNKNOWN ) return UNKNOWN;

		const propertyValue = this.computed ? this.property.getValue() : this.property.name;
		if ( propertyValue === UNKNOWN ) return UNKNOWN;

		const value = objectValue[ propertyValue ];
		if ( value === UNKNOWN || typeof value === 'function' ) return UNKNOWN;

		return value;
	}

	getPrecedence () {
		return 18;
	}

	getRightHandSide () {
		return this;
	}

	minify ( code ) {
		const value = this.getValue();

		if ( value !== UNKNOWN && canFold( this, this.parent ) ) {
			const str = stringify( value );

			if ( str !== null ) {
				code.overwrite( this.start, this.end, str );
				return;
			}
		}

		if ( this.computed ) {
			const value = this.property.getValue();

			if ( String( Number( value ) ) === String( value ) ) {
				code.overwrite( this.object.end, this.end, `[${value}]` );
			}

			else if ( typeof value === 'string' && isValidIdentifier( value ) ) {
				code.overwrite( this.object.end, this.end, `.${value}` );
			}

			else {
				if ( this.property.start > this.object.end + 1 ) {
					code.overwrite( this.object.end, this.property.start, '[' );
				}

				if ( this.end > this.property.end + 1 ) {
					code.overwrite( this.property.end, this.end, ']' );
				}

				this.property.minify( code );
			}
		}

		else {
			if ( this.property.start > this.object.end + 1 ) {
				code.overwrite( this.object.end, this.property.start, '.' );
			}
		}

		this.object.minify( code );
	}
}
<commit_msg>dont fold left hand side of for-in/of loop heads<commit_after>import Node from '../Node.js';
import reserved from '../../utils/reserved.js';
import { UNKNOWN } from '../../utils/sentinels.js';
import stringify from '../../utils/stringify.js';

function isValidIdentifier ( str ) {
	// TODO there's probably a bit more to it than this
	return !reserved[ str ] && /^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test( str );
}

function canFold ( node, parent ) {
	while ( parent.type === 'ParenthesizedExpression' ) {
		node = parent;
		parent = node.parent;
	}

	if ( parent.type === 'UpdateExpression' ) return false;
	if ( parent.type === 'AssignmentExpression' || /For(In|Of)Statement/.test( parent.type ) ) return node !== parent.left;

	return true;
}

export default class MemberExpression extends Node {
	getLeftHandSide () {
		return this.object.getLeftHandSide();
	}

	getValue () {
		const objectValue = this.object.getValue();
		if ( !objectValue || objectValue === UNKNOWN ) return UNKNOWN;

		const propertyValue = this.computed ? this.property.getValue() : this.property.name;
		if ( propertyValue === UNKNOWN ) return UNKNOWN;

		const value = objectValue[ propertyValue ];
		if ( value === UNKNOWN || typeof value === 'function' ) return UNKNOWN;

		return value;
	}

	getPrecedence () {
		return 18;
	}

	getRightHandSide () {
		return this;
	}

	minify ( code ) {
		const value = this.getValue();

		if ( value !== UNKNOWN && canFold( this, this.parent ) ) {
			const str = stringify( value );

			if ( str !== null ) {
				code.overwrite( this.start, this.end, str );
				return;
			}
		}

		if ( this.computed ) {
			const value = this.property.getValue();

			if ( String( Number( value ) ) === String( value ) ) {
				code.overwrite( this.object.end, this.end, `[${value}]` );
			}

			else if ( typeof value === 'string' && isValidIdentifier( value ) ) {
				code.overwrite( this.object.end, this.end, `.${value}` );
			}

			else {
				if ( this.property.start > this.object.end + 1 ) {
					code.overwrite( this.object.end, this.property.start, '[' );
				}

				if ( this.end > this.property.end + 1 ) {
					code.overwrite( this.property.end, this.end, ']' );
				}

				this.property.minify( code );
			}
		}

		else {
			if ( this.property.start > this.object.end + 1 ) {
				code.overwrite( this.object.end, this.property.start, '.' );
			}
		}

		this.object.minify( code );
	}
}
<|endoftext|>


<commit_before>var f = require('file'),
    fs = require('fs'),
    path = require('path'),
    wrench = require('wrench');

var AE86 = function (options) {
    console.log('Revving up AE86\'s ' + options.engine + ' engine...');
    this.options = options;
    var Engine = require('./engines/' + options.engine).Engine;
    this.engine = new Engine();
};
// sync create static, layouts, partials, and pages dirs
AE86.prototype.init = function () {
    console.log('Creating static, layouts, partials, pages directories, and params.js file...');
    f.mkdirsSync(this.options.static, this.options.mode);
    f.mkdirsSync(this.options.layouts, this.options.mode);
    f.mkdirsSync(this.options.partials, this.options.mode);
    f.mkdirsSync(this.options.pages, this.options.mode);
    fs.writeFileSync('params.js', 'exports.params = {\n};', this.options.encoding);
};
// sync delete generated pages
AE86.prototype.clean = function () {
    console.log('Deleting generated pages...');
    wrench.rmdirSyncRecursive(this.options.out);
};
// check if file is to be ignored
AE86.prototype._isIgnored = function (file) {
    var isIgnored = false, item;
    for (item in this.options.ignore) {
        if (file.match(new RegExp('^' + this.options.ignore[item] + '/')) ||
                file.match(new RegExp('/' + this.options.ignore[item] + '/')) ||
                file.match(new RegExp('/' + this.options.ignore[item] + '$'))) {
            isIgnored = true;
            break;
        }
    }
    return isIgnored;
};
// async copy files in static dir to out dir
AE86.prototype._copyStatic = function () {
    var staticDir = this.options.static, outDir = this.options.out, mode = this.options.mode, that = this;
    f.mkdirs(outDir, mode, function () {
        f.walk(staticDir, function (err, orig, dirs, files) {
            if (err) {
                throw err;
            }
            files.forEach(function (file) {
                if (!that._isIgnored(file)) {
                    f.mkdirs(path.dirname(file).replace(staticDir, outDir), mode, function (err) {
                        fs.link(file, file.replace(staticDir, outDir), function (err) {
                            if (err) {
                                throw err;
                            }
                            console.log('\t- ' + file.replace(staticDir, '').replace(/^\//, ''));
                        });
                    });
                }
            });
        });
    });
};
// sync load of files in template dir
AE86.prototype._loadTemplates = function (templateDir) {
    var templates = {}, encoding = this.options.encoding, engine = this.engine, that = this;
    f.walkSync(templateDir, function (origDir, dirs, files) {
        files.forEach(function (file) {
            if (!that._isIgnored(file)) {
                templates[path.join(origDir.replace(templateDir, ''), file).replace(/^\//, '')] =
                    engine.prepare(path.join(origDir, file), encoding);
            }
        });
    });
    return templates;
};
// async write pages merged with layouts, partials, and params
AE86.prototype._writePages = function (layouts, partials, params) {
    var pagesDir = this.options.pages, outDir = this.options.out, mode = this.options.mode,
        encoding = this.options.encoding, engine = this.engine, that = this;
    f.walk(pagesDir, function (err, orig, dirs, files) {
        if (err) {
            throw err;
        }
        files.forEach(function (file) {
            if (!that._isIgnored(file)) {
                f.mkdirs(path.dirname(file).replace(pagesDir, outDir), mode, function (err) {
                    var filePath = file.replace(pagesDir, '').replace(/^\//, '');
                    engine.merge(
                        filePath,
                        engine.prepare(file, encoding),
                        layouts['default'],
                        partials,
                        params,
                        function (data) {
                            fs.writeFile(file.replace(pagesDir, outDir), data, function (err) {
                                if (err) {
                                    throw err;
                                }
                                console.log('\t- ' + filePath);
                            });
                        });
                });
            }
        });
    });
};
AE86.prototype.generate = function () {
    var layouts, partials;

    console.log('Copying static...');
    this._copyStatic();

    console.log('Loading layouts...');
    layouts = this._loadTemplates(this.options.layouts);

    console.log('Loading partials...');
    partials = this._loadTemplates(this.options.partials);

    console.log('Writing pages...');
    this._writePages(layouts, partials, this.options.params);
};

exports.AE86 = AE86;<commit_msg>Added non-directory output dir handling.<commit_after>var f = require('file'),
    fs = require('fs'),
    path = require('path'),
    wrench = require('wrench');

var AE86 = function (options) {
    console.log('Revving up AE86\'s ' + options.engine + ' engine...');
    this.options = options;
    var Engine = require('./engines/' + options.engine).Engine;
    this.engine = new Engine();
};
// sync create static, layouts, partials, and pages dirs
AE86.prototype.init = function () {
    console.log('Creating static, layouts, partials, pages directories, and params.js file...');
    f.mkdirsSync(this.options.static, this.options.mode);
    f.mkdirsSync(this.options.layouts, this.options.mode);
    f.mkdirsSync(this.options.partials, this.options.mode);
    f.mkdirsSync(this.options.pages, this.options.mode);
    fs.writeFileSync('params.js', 'exports.params = {\n};', this.options.encoding);
};
// sync delete generated pages
AE86.prototype.clean = function () {
    console.log('Deleting generated pages...');
    try {
        if (fs.statSync(this.options.out).isDirectory()) {
            wrench.rmdirSyncRecursive(this.options.out);
        } else {
            fs.unlinkSync(this.options.out);
        }
    } catch (e) {
    }
};
// check if file is to be ignored
AE86.prototype._isIgnored = function (file) {
    var isIgnored = false, item;
    for (item in this.options.ignore) {
        if (file.match(new RegExp('^' + this.options.ignore[item] + '/')) ||
                file.match(new RegExp('/' + this.options.ignore[item] + '/')) ||
                file.match(new RegExp('/' + this.options.ignore[item] + '$'))) {
            isIgnored = true;
            break;
        }
    }
    return isIgnored;
};
// async copy files in static dir to out dir
AE86.prototype._copyStatic = function () {
    var staticDir = this.options.static, outDir = this.options.out, mode = this.options.mode, that = this;
    f.mkdirs(outDir, mode, function () {
        f.walk(staticDir, function (err, orig, dirs, files) {
            if (err) {
                throw err;
            }
            files.forEach(function (file) {
                if (!that._isIgnored(file)) {
                    f.mkdirs(path.dirname(file).replace(staticDir, outDir), mode, function (err) {
                        fs.link(file, file.replace(staticDir, outDir), function (err) {
                            if (err) {
                                throw err;
                            }
                            console.log('\t- ' + file.replace(staticDir, '').replace(/^\//, ''));
                        });
                    });
                }
            });
        });
    });
};
// sync load of files in template dir
AE86.prototype._loadTemplates = function (templateDir) {
    var templates = {}, encoding = this.options.encoding, engine = this.engine, that = this;
    f.walkSync(templateDir, function (origDir, dirs, files) {
        files.forEach(function (file) {
            if (!that._isIgnored(file)) {
                templates[path.join(origDir.replace(templateDir, ''), file).replace(/^\//, '')] =
                    engine.prepare(path.join(origDir, file), encoding);
            }
        });
    });
    return templates;
};
// async write pages merged with layouts, partials, and params
AE86.prototype._writePages = function (layouts, partials, params) {
    var pagesDir = this.options.pages, outDir = this.options.out, mode = this.options.mode,
        encoding = this.options.encoding, engine = this.engine, that = this;
    f.walk(pagesDir, function (err, orig, dirs, files) {
        if (err) {
            throw err;
        }
        files.forEach(function (file) {
            if (!that._isIgnored(file)) {
                f.mkdirs(path.dirname(file).replace(pagesDir, outDir), mode, function (err) {
                    var filePath = file.replace(pagesDir, '').replace(/^\//, '');
                    engine.merge(
                        filePath,
                        engine.prepare(file, encoding),
                        layouts['default'],
                        partials,
                        params,
                        function (data) {
                            fs.writeFile(file.replace(pagesDir, outDir), data, function (err) {
                                if (err) {
                                    throw err;
                                }
                                console.log('\t- ' + filePath);
                            });
                        });
                });
            }
        });
    });
};
AE86.prototype.generate = function () {
    var layouts, partials;

    console.log('Copying static...');
    this._copyStatic();

    console.log('Loading layouts...');
    layouts = this._loadTemplates(this.options.layouts);

    console.log('Loading partials...');
    partials = this._loadTemplates(this.options.partials);

    console.log('Writing pages...');
    this._writePages(layouts, partials, this.options.params);
};

exports.AE86 = AE86;<|endoftext|>


<commit_before>/*!
 * module  ajax
 * author  Kael Zhang
 */

var Class = require('class');
var JSON = require('json');
var lang = require('lang');

/**
 * entrance of ajax method
 */
function ajax(url, callback, options){
    var self = this, len = arguments.length;

    // NR.ajax('/hander/?a=avatar&email=i@kael.me', function(rt){...});
    if(self instanceof ajax && callback && len > 1){
        options = options || {};
        options.method = GET;
        options.url = url;

        return new _Ajax(options).on('success', callback).send();

    // ajax.send({a:1});
    // ajax.send({a:2});
    }else{
        return new _Ajax(url);
    }
};

function standardXMLHttpRequest(){
    return new XMLHttpRequest();
};

function isXHRSuccess(xhr){
    var pass = false, s;

    try{
        s = xhr.status;

        // IE sometimes incorrectly returns 1223 which should be 204
        // ref:
        // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
        pass = s >= 200 || s < 300 || s === 1223;

    }catch(e){}

    return pass;
};

function NOOP(){};

function LAMBDA(data){
    return data;
};

function returnTrue(){
    return true;
};

function extendQueryString(query, extra){
    return query + (query.indexOf('?') > -1 ? '&' : '?' ) + extra;
};

/**
  ref: http://www.w3.org/TR/XMLHttpRequest2/#the-xmlhttprequest-interface
    const unsigned short UNSENT = 0;
    const unsigned short OPENED = 1;
    const unsigned short HEADERS_RECEIVED = 2;
    const unsigned short LOADING = 3;
    const unsigned short DONE = 4;
    readonly attribute unsigned short readyState;
 */
var DONE = 4;

var WIN = window;

var EMPTY = '';
var POST = 'POST';
var GET = 'GET';
var STR_JSON = 'json';

var WITH_CREDENTIALS = 'withCredentials';

var REGEX_TRIM_EMPERSAND = /^&+|&+$/;
var REGEX_TRIM_HASH = /#.*$/;

var Xhr = WIN.ActiveXObject ?

    // fallback
    function() {
        if (WIN.XMLHttpRequest) {
            try {
                return standardXMLHttpRequest();
            } catch(e) {}
        }

        try {
            return new WIN.ActiveXObject('Microsoft.XMLHTTP');
        } catch(e) {
        }
    }
:
    standardXMLHttpRequest;

var X_REQUESTED_WITH = {
    'X-Requested-With': 'XMLHttpRequest'
};

var header_presets = {
    Accept: {
        xml     : 'aplication/xml, text/xml',
        html    : 'text/html',
        script  : 'text/javascript, application/javascript',
        json    : 'application/json, text/javascript',
        text    : 'text/plain',
        '*'     : '*/*'
    },

    'X-Request': {
        json    : 'JSON'
    }
};

var response_filter = {
    xml    : 'responseXML',
    text   : 'responseText'
};

// XMLHttpRequest2
var xhr_tester = Xhr();

// progress support
var is_progress_supported = 'onprogress' in xhr_tester;

// credentials support, for cross domain ajax request
var is_credentials_supported = WITH_CREDENTIALS in xhr_tester;

// @private
var _Ajax = Class({
    Implements: 'attrs events',

    initialize: function(options){
        var bind = lang.bind;

        this.set(options);

        this.xhr = Xhr();

        bind('_stateChange', this);

        if(is_progress_supported){
            bind('_loadstart', this);
            bind('_progress', this);
        }
    },

    _stateChange: function(){
        var

        xhr = this.xhr,
        response,
        callback_args;

        if (xhr.readyState === DONE && this.running){
            this.running = false;

            xhr.onreadystatechange = NOOP;

            clearTimeout(this.timer);

            response = this._parseResponse(xhr);
            callback_args = [ response, xhr ];

            this.fire(
                !self.parseError && this.get('isXHRSuccess')(xhr) && this.get('isSuccess')(response) ? 'success' : 'error',
                callback_args
            );
        }
    },

    _parseResponse: function(xhr){
        var

        santitizer  = this.get('santitizer'),
        parser      = this.get('parser'),
        type        = this.get('dataType'),

        rt,
        data_filter = response_filter;

        rt = santitizer(xhr[data_filter[type] || data_filter.text] || xhr[data_filter.text]);

        if(type.indexOf(STR_JSON) > -1){
            try{
                rt = JSON.parse(rt);
                self.parseError = false;

            }catch(e){
                rt = {};
                self.parseError = true;
            }
        }

        return parser(rt);
    },

    send: function(data){
        var method  = this.get('method'),
            url     = this.get('url'),
            timeout = this.get('timeout'),
            user    = this.get('user'),
            async   = this.get('async'),

            xhr = this.xhr;

        this.running = true;

        data = this._tidyRequest(data);

        if(method === GET){

            /**
             * if options.cache is false, force reloading
             */
            if(!this.get('cache')){
                url = extendQueryString(url, '_nr_force=' + lang.guid());
            }

            if(data){
                url = extendQueryString(url, data);
                data = undefined;
            }
        }

        if (is_progress_supported){
            xhr.onloadstart = this._loadstart;
            xhr.onprogress  = this._progress;
        }

        // socket
        if(user){
            xhr.open(method, url, async, user, this.get('password'));

        // passing null username, generates a login popup on Opera
        }else{
            xhr.open(method, url, async);
        }

        /**
         * for firefox 3.5+ and other xmlhttprequest2 supported browsers
         * ref:
         * https://developer.mozilla.org/en/HTTP_access_control#Requests_with_credentials
         * http://www.w3.org/TR/XMLHttpRequest2/#dom-xmlhttprequest-withcredentials
         */
        if (user && WITH_CREDENTIALS in xhr){
            xhr[WITH_CREDENTIALS] = true;
        }

        xhr.onreadystatechange = this._stateChange;

        lang.each(this.get('headers'), function(header, key){

            // for cross domain requests, try/catch is needed
            try {
                xhr.setRequestHeader(key, header);
            } catch (e){}
        });

        this.fire('request');

        xhr.send(data);

        !async && this._stateChange();

        var self = this;

        if(timeout){
            this.timer = setTimeout(function(){
                self.cancel();

            }, timeout);
        }

        return this;
    },

    // @returns {string} query string
    _tidyRequest: function(data){
        data = (data === undefined ? this.get('data') : data) || EMPTY;

        if (lang.isObject(data)){
            data = lang.toQueryString(data);

        }

        return data;
    },

    _loadstart: function(event){
        this.fire('loadstart', [event, this.xhr]);
    },

    _progress: function(event){
        this.fire('progress', [event, this.xhr]);
    },

    cancel: function(){
        var xhr = this.xhr;

        if (this.running){
            this.running = false;

            xhr.abort();
            clearTimeout(this.timer);
            xhr.onreadystatechange = NOOP;

            if (is_progress_supported){
                xhr.onprogress = xhr.onloadstart = NOOP;
            }

            this.xhr = Xhr();
            this.fire('cancel');
        }

        return self;
    }

}, {
    url: {
        value: EMPTY,

        getter: function(v){
            return String(v).replace(REGEX_TRIM_HASH, EMPTY) || location.pathname;
        }
    },

    method: {

        // GET is recommended
        value: GET,

        setter: function(v){
            v = ('' + v).toUpperCase();

            // make sure is uppercase 'GET' or 'POST'
            return v === GET || v === POST ? v : GET;
        }
    },

    // @type {string}
    // if dataType is 'json', an empty responseText will be treated as an Error by default;
    // you can config santitizer option to avoid this:
    //     santitizer -> function(rt){ return rt || {}; }
    dataType: {
        value: STR_JSON,
        setter: function(v){
            return v || '*';
        }
    },

    async: {
        value: true
    },

    timeout: {
        value: 0
    },

    cache: {
        value: false
    },

    user: {
        value: EMPTY
    },

    password: {
        value: EMPTY
    },

    headers: {
        getter: function(headers){
            if(!lang.isObject(headers)){
                headers = {};
            }

            var

            data_type = this.get('dataType'),
            method = this.get('method'),
            presets = header_presets;

            lang.mix(headers, X_REQUESTED_WITH, false);

            lang.each(presets, function(preset, key){
                var header = preset[data_type];

                if(header){
                    headers[key] = header;
                }

                if(method === POST){
                    headers['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
                }
            });

            return headers;
        }
    },

    /**
     * parse the final data
     */
    parser: {
        value: LAMBDA
    },

    /**
     * sanitize the data from the responseText before everything takes its part
     * it will be really useful if the responsed data is nonstandard
     */
    santitizer: {
        value: LAMBDA
    },

    isSuccess: {
        value: returnTrue
    },

    isXHRSuccess: {
        value: isXHRSuccess
    }
});

xhr_tester = null;

module.exports = ajax;

/**
 2013-02-04  Kael:
 - completely migrate to neuron with class attributes
 - fix issue#1

 2011-11-03  Kael:
 - fix a bug about request headers

 2011-10-24  Kael:
 - migrate to Neuron

 2011-08-27  Kael:
 - complete main functionalities
 - minimize the dependency on mootools
 - remove non-standard ecma5 methods
 - dealing with Header:Accepts according to expected data type
 - add some support to XMLHttpRequest2, such as progress, credentials(user, password)
 - add santitizer and parser configurations

 TODO:
 A. add support to xmlParser
 B. add queue supported
 C. add complete cross domain support
 D. check compatibility with XMLHttpRequest2
 E. test Content-type and Accepts

 */<commit_msg>rm lib/ajax.js<commit_after><|endoftext|>


<commit_before>/*global JsonML, jQuery, window */
/*
	JsonFx_Bindings.js
	dynamic behavior binding support

	Created: 2006-11-11-1759
	Modified: 2009-06-20-1342

	Copyright (c)2006-2009 Stephen M. McKamey
	Distributed under an open-source license: http://jsonfx.net/license
*/

/* dependency checks --------------------------------------------*/

/* namespace JsonFx.UI */
var JsonFx;
if ("undefined" === typeof JsonFx) {
	JsonFx = {};
}
if ("undefined" === typeof JsonFx.UI) {
	JsonFx.UI = {};
}

/* singleton JsonFx.Bindings --------------------------------------------*/
JsonFx.Bindings = function() {

	/*object*/ var b = this;
	/*const string*/ var BIND = 1, UNBIND = 2;

	/* build a simple selector lookup structure to very specifically allow lookups without a lot of iterations. */
	/*Dictionary<string,object>*/ var bindings = {};

	/*RegExp*/ var re = /^\s*([\w\-]*|[*])(?:#([\w\-]+)|\.([\w\-]+))?(?:#([\w\-]+)|\.([\w\-]+))?\s*$/;

	/*void*/ b.add = function(/*string*/ selector, /*function(elem)*/ bind, /*function(elem)*/ unbind) {

			if (typeof bind !== "function") {
				bind = null;
			}
			if (typeof unbind !== "function") {
				unbind = null;
			}
			if (!selector || (!bind && !unbind)) {
				return;
			}

			// TODO: cover the case where complex selector contains an inner ','
			var s = selector instanceof Array ?
				selector :
				String(selector).split(',');

			while (s.length > 1) {
				b.add(s.shift(), bind, unbind);
			}
			selector = s.shift();

			s = re.exec(selector);
			if (s) {
				s = {
					tag: (s[1]||"*").toLowerCase(),
					css: (s[3]||s[5]||"*"),
					id: (s[2]||s[4]||"")
				};
			}

			if (s && s.id && s.tag === "*" && s.css === "*") {
				if ("undefined" === typeof bindings["#"]) {
					/*object*/ bindings["#"] = {};
				}

				/*object*/ bindings["#"][s.id] = {};
				bindings["#"][s.id][BIND] = bind;
				bindings["#"][s.id][UNBIND] = unbind;

			} else if (s && !s.id) {
				if ("undefined" === typeof bindings[s.tag]) {
					/*object*/ bindings[s.tag] = {};
				} else if (bindings[s.tag][s.css]) {
					throw new Error("A binding for "+selector+" has already been registered.");
				}

				/*object*/ bindings[s.tag][s.css] = {};
				bindings[s.tag][s.css][BIND] = bind;
				bindings[s.tag][s.css][UNBIND] = unbind;

			} else {
				if ("undefined" === typeof jQuery) {
					// http://www.w3.org/TR/css3-selectors/#simple-selectors
					throw new Error("JsonFx.Bindings requires jQuery to support more than simple tag, class, and id selectors.\nSelector: \""+selector+"\"");
				}

				// delegate complex selectors to jQuery
				if ("undefined" === typeof bindings.$) {
					/*object*/ bindings.$ = {};
				}

				/*object*/ bindings.$[selector] = {};
				bindings.$[selector][BIND] = bind;
				bindings.$[selector][UNBIND] = unbind;
			}
		};

	/*deprecated*/
	/*void*/ b.register = function(/*string*/ tag, /*string*/ css, /*function(elem)*/ bind, /*function(elem)*/ unbind) {
		b.add(tag+'.'+css, bind, unbind);
	};

	/*DOM*/ var performOne = function(/*DOM*/ elem, /*actionKey*/ a) {

			function bindSet(/*object*/ binds, /*string*/ css) {
				if (binds && binds[css] && binds[css][a]) {
					try {
						// perform action on element and
						// allow binding to replace element
						elem = binds[css][a](elem) || elem;
					} catch (ex) {
						var selector = elem.tagName+"."+css;
						if (elem.id) {
							selector += "#"+elem.id;
						}
						alert("Error binding "+selector+" (line "+(ex.lineNumber||ex.line||1)+"):\n\""+(ex&&ex.message||String(ex))+"\"");
						/*jslint debug:true */
						debugger;
						/*jslint debug:false */
					}
				}
			}

			if (elem && elem.tagName) {

				// only perform on registered tags
				var tag = elem.tagName.toLowerCase();
				var allBinds = bindings["*"];
				var tagBinds = bindings[tag];

				if (tagBinds || allBinds) {

					bindSet(tagBinds, "*");
					bindSet(allBinds, "*");

					if (elem.className) {
						// for each css class in elem
						var classes = elem.className.split(/\s+/);
						for (var i=0; i<classes.length; i++) {
							var css = classes[i];
							bindSet(tagBinds, css);
							bindSet(allBinds, css);
						}
					}
				}
			}
			return elem;
		};

	var performOneID = function (/*DOM*/ elem, /*actionKey*/ a) {
			var action = bindings["#"][elem.id];
			action = action && action[a];
			return (action && action(elem)) || elem;
		};

	// perform a binding action on all child elements
	/*void*/ var perform = function(/*DOM*/ root, /*actionKey*/ a) {

	// TODO: add ability to bind on ID, className, tagName or any combination
	// determine how to most efficiently select the smallest set of eligible elements

			/*create a closure for replacement*/
			function queueReplacer(newer, older) {
				setTimeout(function() {
					if (older && older.parentNode) {
						older.parentNode.replaceChild(newer, older);
					}
					// free references
					newer = older = null;
				}, 0);
			}

			function bindTagSet(/*string*/ tag) {
				// for each element in root with tagName
				var elems = root.getElementsByTagName(tag);
				for (var i=0; i<elems.length; i++) {
					// perform action on element and
					// allow binding to replace element
					var replace = performOne(elems[i], a);
					if (replace !== elems[i] && elems[i].parentNode) {
						// queue up replacement at the end so as not to disrupt the list
						queueReplacer(replace, elems[i]);
					}
				}
			}

			root = root || document.body;

			if (bindings.$ && "undefined" !== typeof jQuery) {
				for (var sel in bindings.$) {
					if (bindings.$.hasOwnProperty(sel)) {
						jQuery(sel, root).each(function(foo2) {
							var action = bindings.$[sel];
							action = action && action[a];
							var replace = (action && action(this)) || this;
							if (replace !== this) {
								// queue up replacement at the end so as not to disrupt the list
								queueReplacer(replace, this);
							}
						});
					}
				}
			}

			if (bindings["#"]) {
				for (var id in bindings["#"]) {
					if (bindings["#"].hasOwnProperty(id)) {
						var elem = document.getElementById(id);
						if (!elem) {
							continue;
						}
						var replace = performOneID(elem, a);
						if (replace !== elem) {
							// queue up replacement at the end so as not to disrupt the list
							queueReplacer(replace, elem);
						}
					}
				}
			}

			if (root.getElementsByTagName) {
				if (bindings["*"]) {
					// if star rule, then must apply to all
					bindTagSet("*");
				} else {
					// only apply to tags with rules
					for (var tag in bindings) {
						if (bindings.hasOwnProperty(tag) && tag !== "*" && tag !== "#") {
							bindTagSet(tag);
						}
					}
				}
			}
		};

	// bind
	/*void*/ b.bind = function(/*DOM*/ root) {
		if (!isFinite(root.nodeType)) {
			root = null;
		}

		perform(root, BIND);
	};

	// unbind
	/*void*/ b.unbind = function(/*DOM*/ root) {
		if (!isFinite(root.nodeType)) {
			root = null;
		}

		perform(root, UNBIND);
	};

	// use bindOne as the default JBST filter
	if ("undefined" !== typeof JsonML && JsonML.BST) {
		var bindOne = /*DOM*/ function(/*DOM*/ elem) {
			// apply jQuery bindings
			if (bindings.$ && "undefined" !== typeof jQuery) {
				for (var selector in bindings.$) {
					if (bindings.$.hasOwnProperty(selector) &&
						jQuery(elem).is(selector)) {
							var action = bindings.$[selector];
							action = action && action[BIND];
							elem = (action && action(elem)) || elem;
					}
				}
			}

			// apply ID bindings
			if (performOneID && bindings["#"]) {
				elem = performOneID(elem, BIND);
			}
			// apply tag/css bindings
			elem = performOne(elem, BIND);
			return elem;
		};

		if ("function" !== typeof JsonML.BST.filter) {
			JsonML.BST.filter = bindOne;
		} else {
			JsonML.BST.filter = (function() {
				var old = JsonML.BST.filter;
				return function(/*DOM*/ elem) {
					elem = old(elem);
					return elem && bindOne(elem);
				};
			})();
		}
	}

	// shorthand for auto-replacing an element with JBST bind
	/*void*/ b.replace = function(/*string*/ selector, /*JBST*/ jbst, /*object*/ data, /*int*/ index, /*int*/ count) {
		JsonFx.Bindings.add(
			selector,
			function(elem) {
				return JsonML.BST(jbst).bind(data, index, count) || elem;
			});
	};

	/*void*/ function addHandler(/*DOM*/ target, /*string*/ name, /*function*/ handler) {
		if (typeof jQuery !== "undefined") {
			jQuery(target).bind(name, handler);
		} else if (target.addEventListener) {
			// DOM Level 2 model for binding events
			target.addEventListener(name, handler, false);
		} else if (target.attachEvent) {
			// IE model for binding events
			target.attachEvent("on"+name, handler);
		} else {
			// DOM Level 0 model for binding events
			var old = target["on"+name];
			target["on"+name] = ("function" === typeof old) ?
				function(/*Event*/ evt) { handler(evt); return old(evt); } :
				handler;
		}
	}

	// register bind events
	if ("undefined" !== typeof jQuery) {
		jQuery(b.bind);
	} else {
		addHandler(window, "load", b.bind);
	}
	addHandler(window, "unload", b.unbind);
};

// doing instead of anonymous fn for JSLint compatibility
// instantiate only one, destroying the constructor
JsonFx.Bindings = new JsonFx.Bindings();
<commit_msg>- leveraging jQuery for replacements if available<commit_after>/*global JsonML, jQuery, window */
/*
	JsonFx_Bindings.js
	dynamic behavior binding support

	Created: 2006-11-11-1759
	Modified: 2009-06-20-1342

	Copyright (c)2006-2009 Stephen M. McKamey
	Distributed under an open-source license: http://jsonfx.net/license
*/

/* dependency checks --------------------------------------------*/

/* namespace JsonFx.UI */
var JsonFx;
if ("undefined" === typeof JsonFx) {
	JsonFx = {};
}
if ("undefined" === typeof JsonFx.UI) {
	JsonFx.UI = {};
}

/* singleton JsonFx.Bindings --------------------------------------------*/
JsonFx.Bindings = function() {

	/*object*/ var b = this;
	/*const string*/ var BIND = 1, UNBIND = 2;

	/* build a simple selector lookup structure to very specifically allow lookups without a lot of iterations. */
	/*Dictionary<string,object>*/ var bindings = {};

	/*RegExp*/ var re = /^\s*([\w\-]*|[*])(?:#([\w\-]+)|\.([\w\-]+))?(?:#([\w\-]+)|\.([\w\-]+))?\s*$/;

	/*void*/ b.add = function(/*string*/ selector, /*function(elem)*/ bind, /*function(elem)*/ unbind) {

			if (typeof bind !== "function") {
				bind = null;
			}
			if (typeof unbind !== "function") {
				unbind = null;
			}
			if (!selector || (!bind && !unbind)) {
				return;
			}

			// TODO: cover the case where complex selector contains an inner ','
			var s = selector instanceof Array ?
				selector :
				String(selector).split(',');

			while (s.length > 1) {
				b.add(s.shift(), bind, unbind);
			}
			selector = s.shift();

			s = re.exec(selector);
			if (s) {
				s = {
					tag: (s[1]||"*").toLowerCase(),
					css: (s[3]||s[5]||"*"),
					id: (s[2]||s[4]||"")
				};
			}

			if (s && s.id && s.tag === "*" && s.css === "*") {
				if ("undefined" === typeof bindings["#"]) {
					/*object*/ bindings["#"] = {};
				}

				/*object*/ bindings["#"][s.id] = {};
				bindings["#"][s.id][BIND] = bind;
				bindings["#"][s.id][UNBIND] = unbind;

			} else if (s && !s.id) {
				if ("undefined" === typeof bindings[s.tag]) {
					/*object*/ bindings[s.tag] = {};
				} else if (bindings[s.tag][s.css]) {
					throw new Error("A binding for "+selector+" has already been registered.");
				}

				/*object*/ bindings[s.tag][s.css] = {};
				bindings[s.tag][s.css][BIND] = bind;
				bindings[s.tag][s.css][UNBIND] = unbind;

			} else {
				if ("undefined" === typeof jQuery) {
					// http://www.w3.org/TR/css3-selectors/#simple-selectors
					throw new Error("JsonFx.Bindings requires jQuery to support more than simple tag, class, and id selectors.\nSelector: \""+selector+"\"");
				}

				// delegate complex selectors to jQuery
				if ("undefined" === typeof bindings.$) {
					/*object*/ bindings.$ = {};
				}

				/*object*/ bindings.$[selector] = {};
				bindings.$[selector][BIND] = bind;
				bindings.$[selector][UNBIND] = unbind;
			}
		};

	/*deprecated*/
	/*void*/ b.register = function(/*string*/ tag, /*string*/ css, /*function(elem)*/ bind, /*function(elem)*/ unbind) {
		b.add(tag+'.'+css, bind, unbind);
	};

	/*DOM*/ var performOne = function(/*DOM*/ elem, /*actionKey*/ a) {

			function bindSet(/*object*/ binds, /*string*/ css) {
				if (binds && binds[css] && binds[css][a]) {
					try {
						// perform action on element and
						// allow binding to replace element
						elem = binds[css][a](elem) || elem;
					} catch (ex) {
						var selector = elem.tagName+"."+css;
						if (elem.id) {
							selector += "#"+elem.id;
						}
						alert("Error binding "+selector+" (line "+(ex.lineNumber||ex.line||1)+"):\n\""+(ex&&ex.message||String(ex))+"\"");
						/*jslint debug:true */
						debugger;
						/*jslint debug:false */
					}
				}
			}

			if (elem && elem.tagName) {

				// only perform on registered tags
				var tag = elem.tagName.toLowerCase();
				var allBinds = bindings["*"];
				var tagBinds = bindings[tag];

				if (tagBinds || allBinds) {

					bindSet(tagBinds, "*");
					bindSet(allBinds, "*");

					if (elem.className) {
						// for each css class in elem
						var classes = elem.className.split(/\s+/);
						for (var i=0; i<classes.length; i++) {
							var css = classes[i];
							bindSet(tagBinds, css);
							bindSet(allBinds, css);
						}
					}
				}
			}
			return elem;
		};

	var performOneID = function (/*DOM*/ elem, /*actionKey*/ a) {
			var action = bindings["#"][elem.id];
			action = action && action[a];
			return (action && action(elem)) || elem;
		};

	// perform a binding action on all child elements
	/*void*/ var perform = function(/*DOM*/ root, /*actionKey*/ a) {

	// TODO: add ability to bind on ID, className, tagName or any combination
	// determine how to most efficiently select the smallest set of eligible elements

			/*create a closure for replacement*/
			function queueReplacer(newer, older) {
				setTimeout(function() {
					if (older && older.parentNode) {
						older.parentNode.replaceChild(newer, older);
					}
					// free references
					newer = older = null;
				}, 0);
			}

			function bindTagSet(/*string*/ tag) {
				// for each element in root with tagName
				var elems = root.getElementsByTagName(tag);
				for (var i=0; i<elems.length; i++) {
					// perform action on element and
					// allow binding to replace element
					var replace = performOne(elems[i], a);
					if (replace !== elems[i] && elems[i].parentNode) {
						// queue up replacement at the end so as not to disrupt the list
						queueReplacer(replace, elems[i]);
					}
				}
			}

			root = root || document.body;

			if (bindings.$ && "undefined" !== typeof jQuery) {
				for (var sel in bindings.$) {
					if (bindings.$.hasOwnProperty(sel)) {
						jQuery(sel, root).each(function(foo2) {
							var action = bindings.$[sel];
							action = action && action[a];
							var replace = (action && action(this)) || this;
							if (replace !== this) {
								// queue up replacement at the end so as not to disrupt the list
								queueReplacer(replace, this);
							}
						});
					}
				}
			}

			if (bindings["#"]) {
				for (var id in bindings["#"]) {
					if (bindings["#"].hasOwnProperty(id)) {
						var elem = document.getElementById(id);
						if (!elem) {
							continue;
						}
						var replace = performOneID(elem, a);
						if (replace !== elem) {
							// queue up replacement at the end so as not to disrupt the list
							queueReplacer(replace, elem);
						}
					}
				}
			}

			if (root.getElementsByTagName) {
				if (bindings["*"]) {
					// if star rule, then must apply to all
					bindTagSet("*");
				} else {
					// only apply to tags with rules
					for (var tag in bindings) {
						if (bindings.hasOwnProperty(tag) && tag !== "*" && tag !== "#") {
							bindTagSet(tag);
						}
					}
				}
			}
		};

	// bind
	/*void*/ b.bind = function(/*DOM*/ root) {
		if (!isFinite(root.nodeType)) {
			root = null;
		}

		perform(root, BIND);
	};

	// unbind
	/*void*/ b.unbind = function(/*DOM*/ root) {
		if (!isFinite(root.nodeType)) {
			root = null;
		}

		perform(root, UNBIND);
	};

	// use bindOne as the default JBST filter
	if ("undefined" !== typeof JsonML && JsonML.BST) {
		var bindOne = /*DOM*/ function(/*DOM*/ elem) {
			// apply jQuery bindings
			if (bindings.$ && "undefined" !== typeof jQuery) {
				for (var selector in bindings.$) {
					if (bindings.$.hasOwnProperty(selector) &&
						jQuery(elem).is(selector)) {
							var action = bindings.$[selector];
							action = action && action[BIND];
							elem = (action && action(elem)) || elem;
					}
				}
			}

			// apply ID bindings
			if (performOneID && bindings["#"]) {
				elem = performOneID(elem, BIND);
			}
			// apply tag/css bindings
			elem = performOne(elem, BIND);
			return elem;
		};

		if ("function" !== typeof JsonML.BST.filter) {
			JsonML.BST.filter = bindOne;
		} else {
			JsonML.BST.filter = (function() {
				var old = JsonML.BST.filter;
				return function(/*DOM*/ elem) {
					elem = old(elem);
					return elem && bindOne(elem);
				};
			})();
		}
	}

	// shorthand for auto-replacing an element with JBST bind
	/*void*/ b.replace = function(/*string*/ selector, /*JBST*/ jbst, /*object*/ data, /*int*/ index, /*int*/ count) {
		if ("undefined" !== typeof jQuery) {
			jQuery(function() {
				var elem = jQuery(selector);
				if (elem.length) {
					elem.replaceWith(JsonML.BST(jbst).bind(data, index, count));
				}
			});
		} else {
			JsonFx.Bindings.add(
				selector,
				function(elem) {
					return JsonML.BST(jbst).bind(data, index, count) || elem;
				});
		}
	};

	/*void*/ function addHandler(/*DOM*/ target, /*string*/ name, /*function*/ handler) {
		if (typeof jQuery !== "undefined") {
			jQuery(target).bind(name, handler);
		} else if (target.addEventListener) {
			// DOM Level 2 model for binding events
			target.addEventListener(name, handler, false);
		} else if (target.attachEvent) {
			// IE model for binding events
			target.attachEvent("on"+name, handler);
		} else {
			// DOM Level 0 model for binding events
			var old = target["on"+name];
			target["on"+name] = ("function" === typeof old) ?
				function(/*Event*/ evt) { handler(evt); return old(evt); } :
				handler;
		}
	}

	// register bind events
	if ("undefined" !== typeof jQuery) {
		jQuery(b.bind);
	} else {
		addHandler(window, "load", b.bind);
	}
	addHandler(window, "unload", b.unbind);
};

// doing instead of anonymous fn for JSLint compatibility
// instantiate only one, destroying the constructor
JsonFx.Bindings = new JsonFx.Bindings();
<|endoftext|>