<commit_before>#!/usr/bin/env node
var path = require('path')
var fs = require('fs')
var program = require('commander')
var chalk = require('chalk')
var xml2js = require('xml2js')
var open = require('open')
var exec = require('./utils/exec').exec
var auth = require('./utils/auth')
var github = require('./utils/github')
var getSkpmConfigFromPackageJSON = require('./utils/getSkpmConfigFromPackageJSON')
var extractRepository = require('./utils/extractRepository')

var EMPTY_APPCAST = {
  rss: {
    $: {
      'xmlns:sparkle': 'http://www.andymatuschak.org/xml-namespaces/sparkle',
      'xmlns:dc': 'http://purl.org/dc/elements/1.1/',
      version: '2.0'
    },
    channel: [{ item: [] }]
  }
}

program
  .description('Publish a new version of the plugin')
  .usage('[options] <bump>')
  .option('-o, --open-release', 'Open the newly created release on Github.com')
  .option('-n, --no-registry', 'Do not push to the registry')
  .option('-u, --repo-url <repoURL>', 'Specify the repository URL (default to the one specified in package.json)')
  .arguments('<bump>')
  .action(function (bump) {
    program.bump = bump
  })
  .parse(process.argv)

var token

var packageJSON
try {
  packageJSON = require(path.join(process.cwd(), 'package.json'))
} catch (err) {
  console.error(chalk.red('error') + ' Error while reading the package.json file')
  console.error(err)
  process.exit(1)
}

var skpmConfig = getSkpmConfigFromPackageJSON

if (!skpmConfig.name) {
  console.error(chalk.red('error') + ' Missing "name" field in the package.json.')
  process.exit(1)
}

var repo = (program.repoUrl && extractRepository((program.repoUrl))) || packageJSON

if (!repo) {
  console.error(chalk.red('error') + ' Missing "repository" field in the package.json.')
  process.exit(1)
}

var script = (packageJSON.scripts || {}).prepublish && 'prepublish'
if (!script) {
  script = (packageJSON.scripts || {}).build && 'build'
}

var tempZip = Date.now() + '.zip'
var tag
var releaseId

var step = 0
var steps = 8
if (script) {
  steps += 1
}
if (!program.noRegistry && !packageJSON.private) {
  steps += 1
}
if (typeof program.bump === 'undefined') {
  steps -= 3
  tag = skpmConfig.version
}

console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🗝  Checking if `' + repo + '` is accessible...')

auth.getToken().then(function (_token) {
  token = _token
  return github.getRepo(token, repo)
})
.catch(function (err) {
  console.error(chalk.red('error') + ' Token invalid')
  console.error(err)
  process.exit(1)
})
.then(function () {
  if (typeof program.bump === 'undefined') {
    return
  }
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🏷  Bumping package.json version and creating git tag...')
  return exec('npm version ' + program.bump + ' -m "Publish %s release :rocket:"')
})
.then(function (res) {
  if (typeof program.bump === 'undefined') {
    return
  }
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🗂  Updating the appcast file...')
  tag = res.stdout.trim()
  var appcast = path.join(process.cwd(), '.appcast.xml')
  return new Promise(function (resolve, reject) {
    fs.readFile(appcast, function (err, data) {
      if (err) {
        return resolve(EMPTY_APPCAST)
      }
      xml2js.parseString(data, function (err, result) {
        if (err) {
          return resolve(EMPTY_APPCAST)
        }
        resolve(result)
      })
    })
  }).then(function (appcastObj) {
    appcastObj.rss.channel[0].item.unshift({
      enclosure: [{
        $: {
          url: 'https://github.com/' + repo + '/releases/download/' + tag + '/' + path.basename(skpmConfig.main) + '.zip',
          'sparkle:version': tag.replace('v', '')
        }
      }]
    })
    var builder = new xml2js.Builder()
    return builder.buildObject(appcastObj)
  }).then(function (xml) {
    return new Promise(function (resolve, reject) {
      fs.writeFile(appcast, xml, function (err, data) {
        if (err) {
          return reject(err)
        }
        resolve(data)
      })
    })
  }).then(function () {
    return exec('git add "' + appcast + '"')
  }).then(function () {
    return exec('git commit -m "Update .appcast with new tag :sparkles:"')
  })
})
.then(function (res) {
  if (typeof program.bump === 'undefined') {
    return
  }
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 📤  Pushing the created tag to Github...')
  return exec('git push -f origin HEAD ' + tag)
})
.then(function (res) {
  if (!script) { return }
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🛠  Building the plugin...')
  return exec('npm run ' + script)
})
.then(function (res) {
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 📦  Zipping the plugin...')
  return exec('zip -r ' + tempZip + ' ' + skpmConfig.main + ' -x "*.DS_Store"')
})
.then(function (res) {
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 📝  Creating a draft release on Github...')
  return github.createDraftRelease(token, repo, tag)
})
.then(function (res) {
  releaseId = res.id
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🚀  Uploading zip asset...')
  return github.updateAsset(token, repo, releaseId, tempZip, path.basename(skpmConfig.main) + '.zip')
})
.then(function () {
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🎉  Publishing the release...')
  return github.publishRelease(token, repo, releaseId)
})
.then(function (res) {
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🗑  Removing the local zip...')
  return exec('rm -f ' + tempZip)
})
.then(function () {
  if (!program.noRegistry && !packageJSON.private) {
    console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🔔  Publishing the plugin on the official plugin directory...')
    return github.addPluginToPluginsRegistryRepo(token, packageJSON, repo)
  }
})
.then(function (res) {
  console.log(chalk.green('success') + ' Plugin published')
  console.log(skpmConfig.name + '@' + tag.replace('v', ''))
  if (program.openRelease) {
    open('https://github.com/' + repo + '/tag/' + tag.replace('v', ''))
  }
  process.exit(0)
})
.catch(function (err) {
  console.error(chalk.red('error') + ' Publication failed')
  console.error(err)
  process.exit(1)
})
<commit_msg>Correct repository error (see #55)<commit_after>#!/usr/bin/env node
var path = require('path')
var fs = require('fs')
var program = require('commander')
var chalk = require('chalk')
var xml2js = require('xml2js')
var open = require('open')
var exec = require('./utils/exec').exec
var auth = require('./utils/auth')
var github = require('./utils/github')
var getSkpmConfigFromPackageJSON = require('./utils/getSkpmConfigFromPackageJSON')
var extractRepository = require('./utils/extractRepository')

var EMPTY_APPCAST = {
  rss: {
    $: {
      'xmlns:sparkle': 'http://www.andymatuschak.org/xml-namespaces/sparkle',
      'xmlns:dc': 'http://purl.org/dc/elements/1.1/',
      version: '2.0'
    },
    channel: [{ item: [] }]
  }
}

program
  .description('Publish a new version of the plugin')
  .usage('[options] <bump>')
  .option('-o, --open-release', 'Open the newly created release on Github.com')
  .option('-n, --no-registry', 'Do not push to the registry')
  .option('-u, --repo-url <repoURL>', 'Specify the repository URL (default to the one specified in package.json)')
  .arguments('<bump>')
  .action(function (bump) {
    program.bump = bump
  })
  .parse(process.argv)

var token

var packageJSON
try {
  packageJSON = require(path.join(process.cwd(), 'package.json'))
} catch (err) {
  console.error(chalk.red('error') + ' Error while reading the package.json file')
  console.error(err)
  process.exit(1)
}

var skpmConfig = getSkpmConfigFromPackageJSON(packageJSON)

if (!skpmConfig.name) {
  console.error(chalk.red('error') + ' Missing "name" field in the package.json.')
  process.exit(1)
}

var repo = (program.repoUrl && extractRepository((program.repoUrl))) || skpmConfig.repository

if (!repo) {
  console.error(chalk.red('error') + ' Missing "repository" field in the package.json.')
  process.exit(1)
}

var script = (packageJSON.scripts || {}).prepublish && 'prepublish'
if (!script) {
  script = (packageJSON.scripts || {}).build && 'build'
}

var tempZip = Date.now() + '.zip'
var tag
var releaseId

var step = 0
var steps = 8
if (script) {
  steps += 1
}
if (!program.noRegistry && !packageJSON.private) {
  steps += 1
}
if (typeof program.bump === 'undefined') {
  steps -= 3
  tag = skpmConfig.version
}

console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🗝  Checking if `' + repo + '` is accessible...')

auth.getToken().then(function (_token) {
  token = _token
  return github.getRepo(token, repo)
})
.catch(function (err) {
  console.error(chalk.red('error') + ' Token invalid')
  console.error(err)
  process.exit(1)
})
.then(function () {
  if (typeof program.bump === 'undefined') {
    return
  }
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🏷  Bumping package.json version and creating git tag...')
  return exec('npm version ' + program.bump + ' -m "Publish %s release :rocket:"')
})
.then(function (res) {
  if (typeof program.bump === 'undefined') {
    return
  }
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🗂  Updating the appcast file...')
  tag = res.stdout.trim()
  var appcast = path.join(process.cwd(), '.appcast.xml')
  return new Promise(function (resolve, reject) {
    fs.readFile(appcast, function (err, data) {
      if (err) {
        return resolve(EMPTY_APPCAST)
      }
      xml2js.parseString(data, function (err, result) {
        if (err) {
          return resolve(EMPTY_APPCAST)
        }
        resolve(result)
      })
    })
  }).then(function (appcastObj) {
    appcastObj.rss.channel[0].item.unshift({
      enclosure: [{
        $: {
          url: 'https://github.com/' + repo + '/releases/download/' + tag + '/' + path.basename(skpmConfig.main) + '.zip',
          'sparkle:version': tag.replace('v', '')
        }
      }]
    })
    var builder = new xml2js.Builder()
    return builder.buildObject(appcastObj)
  }).then(function (xml) {
    return new Promise(function (resolve, reject) {
      fs.writeFile(appcast, xml, function (err, data) {
        if (err) {
          return reject(err)
        }
        resolve(data)
      })
    })
  }).then(function () {
    return exec('git add "' + appcast + '"')
  }).then(function () {
    return exec('git commit -m "Update .appcast with new tag :sparkles:"')
  })
})
.then(function (res) {
  if (typeof program.bump === 'undefined') {
    return
  }
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 📤  Pushing the created tag to Github...')
  return exec('git push -f origin HEAD ' + tag)
})
.then(function (res) {
  if (!script) { return }
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🛠  Building the plugin...')
  return exec('npm run ' + script)
})
.then(function (res) {
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 📦  Zipping the plugin...')
  return exec('zip -r ' + tempZip + ' ' + skpmConfig.main + ' -x "*.DS_Store"')
})
.then(function (res) {
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 📝  Creating a draft release on Github...')
  return github.createDraftRelease(token, repo, tag)
})
.then(function (res) {
  releaseId = res.id
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🚀  Uploading zip asset...')
  return github.updateAsset(token, repo, releaseId, tempZip, path.basename(skpmConfig.main) + '.zip')
})
.then(function () {
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🎉  Publishing the release...')
  return github.publishRelease(token, repo, releaseId)
})
.then(function (res) {
  console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🗑  Removing the local zip...')
  return exec('rm -f ' + tempZip)
})
.then(function () {
  if (!program.noRegistry && !packageJSON.private) {
    console.log(chalk.dim('[' + (++step) + '/' + steps + ']') + ' 🔔  Publishing the plugin on the official plugin directory...')
    return github.addPluginToPluginsRegistryRepo(token, packageJSON, repo)
  }
})
.then(function (res) {
  console.log(chalk.green('success') + ' Plugin published')
  console.log(skpmConfig.name + '@' + tag.replace('v', ''))
  if (program.openRelease) {
    open('https://github.com/' + repo + '/tag/' + tag.replace('v', ''))
  }
  process.exit(0)
})
.catch(function (err) {
  console.error(chalk.red('error') + ' Publication failed')
  console.error(err)
  process.exit(1)
})
<|endoftext|>


<commit_before>var path = require('path');
var Promise = require('any-promise');
var bindings = require('../build/Release/spellchecker.node');

var Spellchecker = bindings.Spellchecker;

var checkSpellingAsyncCb = Spellchecker.prototype.checkSpellingAsync

Spellchecker.prototype.checkSpellingAsync = function (corpus) {
  return new Promise(function (resolve, reject) {
    checkSpellingAsyncCb.call(this, corpus, function (err, result) {
      if (err) {
        reject(err);
      } else {
        resolve(result);
      }
    });
  }.bind(this));
};

var defaultSpellcheck = null;

var ensureDefaultSpellCheck = function() {
  if (defaultSpellcheck) {
    return;
  }

  var lang = process.env.LANG;
  lang = lang ? lang.split('.')[0] : 'en_US';
  defaultSpellcheck = new Spellchecker();

  setDictionary(lang, getDictionaryPath());
};

var setDictionary = function(lang, dictPath) {
  ensureDefaultSpellCheck();
  return defaultSpellcheck.setDictionary(lang, dictPath);
};

var isMisspelled = function() {
  ensureDefaultSpellCheck();

  return defaultSpellcheck.isMisspelled.apply(defaultSpellcheck, arguments);
};

var checkSpelling = function() {
  ensureDefaultSpellCheck();

  return defaultSpellcheck.checkSpelling.apply(defaultSpellcheck, arguments);
};

var checkSpellingAsync = function(corpus) {
  ensureDefaultSpellCheck();

  return defaultSpellcheck.checkSpellingAsync.apply(defaultSpellcheck, arguments);
};

var add = function() {
  ensureDefaultSpellCheck();

  defaultSpellcheck.add.apply(defaultSpellcheck, arguments);
};

var remove = function() {
  ensureDefaultSpellCheck();

  defaultSpellcheck.remove.apply(defaultSpellcheck, arguments);
};

var getCorrectionsForMisspelling = function() {
  ensureDefaultSpellCheck();

  return defaultSpellcheck.getCorrectionsForMisspelling.apply(defaultSpellcheck, arguments);
};

var getAvailableDictionaries = function() {
  ensureDefaultSpellCheck();

  return defaultSpellcheck.getAvailableDictionaries.apply(defaultSpellcheck, arguments);
};

var getDictionaryPath = function() {
  var dict = path.join(__dirname, '..', 'vendor', 'hunspell_dictionaries');
  try {
    // HACK: Special case being in an asar archive
    var unpacked = dict.replace('.asar' + path.sep, '.asar.unpacked' + path.sep);
    if (require('fs').statSyncNoException(unpacked)) {
      dict = unpacked;
    }
  } catch (error) {
  }
  return dict;
}

module.exports = {
  setDictionary: setDictionary,
  add: add,
  remove: remove,
  isMisspelled: isMisspelled,
  checkSpelling: checkSpelling,
  checkSpellingAsync: checkSpellingAsync,
  getAvailableDictionaries: getAvailableDictionaries,
  getCorrectionsForMisspelling: getCorrectionsForMisspelling,
  getDictionaryPath: getDictionaryPath,
  Spellchecker: Spellchecker
};
<commit_msg>Remove usage of fs.statSyncNoException, deprecated in Electron 3.0<commit_after>var path = require('path');
var Promise = require('any-promise');
var bindings = require('../build/Release/spellchecker.node');

var Spellchecker = bindings.Spellchecker;

var checkSpellingAsyncCb = Spellchecker.prototype.checkSpellingAsync

Spellchecker.prototype.checkSpellingAsync = function (corpus) {
  return new Promise(function (resolve, reject) {
    checkSpellingAsyncCb.call(this, corpus, function (err, result) {
      if (err) {
        reject(err);
      } else {
        resolve(result);
      }
    });
  }.bind(this));
};

var defaultSpellcheck = null;

var ensureDefaultSpellCheck = function() {
  if (defaultSpellcheck) {
    return;
  }

  var lang = process.env.LANG;
  lang = lang ? lang.split('.')[0] : 'en_US';
  defaultSpellcheck = new Spellchecker();

  setDictionary(lang, getDictionaryPath());
};

var setDictionary = function(lang, dictPath) {
  ensureDefaultSpellCheck();
  return defaultSpellcheck.setDictionary(lang, dictPath);
};

var isMisspelled = function() {
  ensureDefaultSpellCheck();

  return defaultSpellcheck.isMisspelled.apply(defaultSpellcheck, arguments);
};

var checkSpelling = function() {
  ensureDefaultSpellCheck();

  return defaultSpellcheck.checkSpelling.apply(defaultSpellcheck, arguments);
};

var checkSpellingAsync = function(corpus) {
  ensureDefaultSpellCheck();

  return defaultSpellcheck.checkSpellingAsync.apply(defaultSpellcheck, arguments);
};

var add = function() {
  ensureDefaultSpellCheck();

  defaultSpellcheck.add.apply(defaultSpellcheck, arguments);
};

var remove = function() {
  ensureDefaultSpellCheck();

  defaultSpellcheck.remove.apply(defaultSpellcheck, arguments);
};

var getCorrectionsForMisspelling = function() {
  ensureDefaultSpellCheck();

  return defaultSpellcheck.getCorrectionsForMisspelling.apply(defaultSpellcheck, arguments);
};

var getAvailableDictionaries = function() {
  ensureDefaultSpellCheck();

  return defaultSpellcheck.getAvailableDictionaries.apply(defaultSpellcheck, arguments);
};

var getDictionaryPath = function() {
  var dict = path.join(__dirname, '..', 'vendor', 'hunspell_dictionaries');
  try {
    // HACK: Special case being in an asar archive
    var unpacked = dict.replace('.asar' + path.sep, '.asar.unpacked' + path.sep);
    if (require('fs').statSync(unpacked)) {
      dict = unpacked;
    }
  } catch (error) {
    // When the dictionary isn't contained within an .asar, return the original path.
  }
  return dict;
}

module.exports = {
  setDictionary: setDictionary,
  add: add,
  remove: remove,
  isMisspelled: isMisspelled,
  checkSpelling: checkSpelling,
  checkSpellingAsync: checkSpellingAsync,
  getAvailableDictionaries: getAvailableDictionaries,
  getCorrectionsForMisspelling: getCorrectionsForMisspelling,
  getDictionaryPath: getDictionaryPath,
  Spellchecker: Spellchecker
};
<|endoftext|>


<commit_before>const LOG_LEVELS = {
    HARD_ERROR: 0,  // system level critical error: hardError
    ERROR: 1,  // potentially causing user's data loosing error: error
    LOG_ERROR: 2,  // minor annoyance, recoverable error:   logError
    UX_ERROR: 3,  // user experience causing issues error:  uxError
    WARN: 4,  // warning,possible isues but somehow unclear behaviour: warn
    INFO: 5,  // store general info about the system working: info
    DEBUG: 6,  // system level debug: debug
    LOCAL_DEBUG: 7,  // local node/service debug: ldebug
    USER_DEBUG: 8,  // user level debug; udebug
    DEV_DEBUG: 9,  // development time debug: ddebug
    WHYS: 10, // whyLog for code reasoning
    TEST_RESULT: 11, // testResult to log running tests
};

exports.init = function (sf) {

    /**
     * Records log messages from various use cases.
     * @param record {String} - log message.
     */
    sf.logger.record = function (record) {
        const triggerStrings = ["pskruntime", "double-check"];
        var displayOnConsole = true;
        if (process.send) {
            process.send(record);
            displayOnConsole = false;
        }

        function removeLines(str, nb) {
            function removeLine(str,  force) {
                var pos = str.indexOf("\n");
                var willBeRemoved = str.slice(0, pos);

                if (!force) {
                    var foundMatch = false;
                    for(var i=0; i< triggerStrings.length;i++){
                        let item = triggerStrings[i];
                        if (willBeRemoved.indexOf(item) != -1) {
                            foundMatch = true;
                        }
                    }
                    if (!foundMatch) {
                        throw foundMatch;
                    }
                }
                return str.slice(pos + 1, str.length);
            }

            let ret = str;
            for (let v = 0; v < nb; v++) {
                try {
                    ret = removeLine(ret, v==0);
                } catch (err) {
                    // nothing... exit for
                }
            }
            return ret;
        }

        if (displayOnConsole) {
            //const prettyLog = JSON.stringify(record, null, 2);
            //console.log(prettyLog);
            console.log(record.message);
            if (record.stack) {
                var pos = record.stack.indexOf("\n");
                var message = record.stack.slice(0, pos);
                console.log(message);
                console.log(removeLines(record.stack, 3));
            }
        }
    };

    /**
     * Adding case for logging system level critical errors.
     */
    sf.logger.addCase('hardError', function (message, exception, args, pos, data) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.HARD_ERROR, 'systemError', message, exception, true, args, pos, data));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging potentially causing user's data loosing errors.
     */
    sf.logger.addCase('error', function (message, exception, args, pos, data) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.ERROR, 'error', message, exception, true, args, pos, data));
    }, [
        {
            'message': 'explanation'
        },
        {
            'exception': 'exception'
        }
    ]);

    /**
     * Adding case for logging minor annoyance, recoverable errors.
     */
    sf.logger.addCase('logError', function (message, exception, args, pos, data) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.LOG_ERROR, 'logError', message, exception, true, args, pos, data));
    }, [
        {
            'message': 'explanation'
        },
        {
            'exception': 'exception'
        }
    ]);

    /**
     * Adding case for logging user experience causing issues errors.
     */
    sf.logger.addCase('uxError', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.UX_ERROR, 'uxError', message, null, false));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging throttling messages.
     */
    sf.logger.addCase('throttling', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.WARN, 'throttling', message, null, false));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging warning, possible issues, but somehow unclear behaviours.
     */
    sf.logger.addCase('warning', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.WARN, 'warning', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    sf.logger.alias('warn', 'warning');

    /**
     * Adding case for logging general info about the system working.
     */
    sf.logger.addCase('info', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.INFO, 'info', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging system level debug messages.
     */
    sf.logger.addCase('debug', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.DEBUG, 'debug', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging local node/service debug messages.
     */
    sf.logger.addCase('ldebug', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.LOCAL_DEBUG, 'ldebug', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging user level debug messages.
     */
    sf.logger.addCase('udebug', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.USER_DEBUG, 'udebug', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging development debug messages.
     */
    sf.logger.addCase('devel', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.DEV_DEBUG, 'devel', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging "whys" reasoning messages.
     */
    sf.logger.addCase("logWhy", function (logOnlyCurrentWhyContext) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.WHYS, 'logwhy', undefined, undefined, undefined, undefined, undefined, undefined, logOnlyCurrentWhyContext));
    });

    /**
     * Adding case for logging asserts messages to running tests.
     */
    sf.logger.addCase("recordAssert", function (message, error, showStack) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.TEST_RESULT, 'assert', message, error, showStack));
    });

    /**
     * Generic method to create structured debug records based on the log level.
     * @param level {Number} - number from 1-11, used to identify the level of attention that a log entry should get from operations point of view
     * @param type {String} - identifier name for log type
     * @param message {String} - description of the debug record
     * @param exception {String} - exception details if any
     * @param saveStack {Boolean} - if set to true, the exception call stack will be added to the debug record
     * @param args {Array} - arguments of the caller function
     * @param pos {Number} - position
     * @param data {String|Number|Array|Object} - payload information
     * @param logOnlyCurrentWhyContext - if whys is enabled, only the current context will be logged
     * @returns Debug record model {Object} with the following fields:
     * [required]: level: *, type: *, timestamp: number, message: *, data: * and
     * [optional]: stack: *, exception: *, args: *, whyLog: *
     */
    function createDebugRecord(level, type, message, exception, saveStack, args, pos, data, logOnlyCurrentWhyContext) {

        var ret = {
            level: level,
            type: type,
            timestamp: (new Date()).getTime(),
            message: message
        };

        if(data){
            ret.data = data;
        }

        if (saveStack) {
            var stack = '';
            if (exception) {
                stack = exception.stack;
            } else {
                stack = (new Error()).stack;
            }
            ret.stack = stack;
        }

        if (exception) {
            ret.exception = exception.message;
        }

        if (args) {
            ret.args = JSON.parse(JSON.stringify(args));
        }

        if (process.env.RUN_WITH_WHYS) {
            var why = require('whys');
            if (logOnlyCurrentWhyContext) {
                ret['whyLog'] = why.getGlobalCurrentContext().getExecutionSummary();
            } else {
                ret['whyLog'] = why.getAllContexts().map(function (context) {
                    return context.getExecutionSummary();
                });
            }
        }
        return ret;
    }

}
;

<commit_msg>Write to stderr when logger gets a stack<commit_after>const LOG_LEVELS = {
    HARD_ERROR: 0,  // system level critical error: hardError
    ERROR: 1,  // potentially causing user's data loosing error: error
    LOG_ERROR: 2,  // minor annoyance, recoverable error:   logError
    UX_ERROR: 3,  // user experience causing issues error:  uxError
    WARN: 4,  // warning,possible isues but somehow unclear behaviour: warn
    INFO: 5,  // store general info about the system working: info
    DEBUG: 6,  // system level debug: debug
    LOCAL_DEBUG: 7,  // local node/service debug: ldebug
    USER_DEBUG: 8,  // user level debug; udebug
    DEV_DEBUG: 9,  // development time debug: ddebug
    WHYS: 10, // whyLog for code reasoning
    TEST_RESULT: 11, // testResult to log running tests
};

exports.init = function (sf) {

    /**
     * Records log messages from various use cases.
     * @param record {String} - log message.
     */
    sf.logger.record = function (record) {
        const triggerStrings = ["pskruntime", "double-check"];
        var displayOnConsole = true;
        if (process.send) {
            process.send(record);
            displayOnConsole = false;
        }

        function removeLines(str, nb) {
            function removeLine(str,  force) {
                var pos = str.indexOf("\n");
                var willBeRemoved = str.slice(0, pos);

                if (!force) {
                    var foundMatch = false;
                    for(var i=0; i< triggerStrings.length;i++){
                        let item = triggerStrings[i];
                        if (willBeRemoved.indexOf(item) != -1) {
                            foundMatch = true;
                        }
                    }
                    if (!foundMatch) {
                        throw foundMatch;
                    }
                }
                return str.slice(pos + 1, str.length);
            }

            let ret = str;
            for (let v = 0; v < nb; v++) {
                try {
                    ret = removeLine(ret, v==0);
                } catch (err) {
                    // nothing... exit for
                }
            }
            return ret;
        }

        if (displayOnConsole) {
            //const prettyLog = JSON.stringify(record, null, 2);
            //console.log(prettyLog);
            console.log(record.message);
            if (record.stack) {
                var pos = record.stack.indexOf("\n");
                var message = record.stack.slice(0, pos);
                console.error(message);
                console.error(removeLines(record.stack, 3));
            }
        }
    };

    /**
     * Adding case for logging system level critical errors.
     */
    sf.logger.addCase('hardError', function (message, exception, args, pos, data) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.HARD_ERROR, 'systemError', message, exception, true, args, pos, data));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging potentially causing user's data loosing errors.
     */
    sf.logger.addCase('error', function (message, exception, args, pos, data) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.ERROR, 'error', message, exception, true, args, pos, data));
    }, [
        {
            'message': 'explanation'
        },
        {
            'exception': 'exception'
        }
    ]);

    /**
     * Adding case for logging minor annoyance, recoverable errors.
     */
    sf.logger.addCase('logError', function (message, exception, args, pos, data) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.LOG_ERROR, 'logError', message, exception, true, args, pos, data));
    }, [
        {
            'message': 'explanation'
        },
        {
            'exception': 'exception'
        }
    ]);

    /**
     * Adding case for logging user experience causing issues errors.
     */
    sf.logger.addCase('uxError', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.UX_ERROR, 'uxError', message, null, false));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging throttling messages.
     */
    sf.logger.addCase('throttling', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.WARN, 'throttling', message, null, false));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging warning, possible issues, but somehow unclear behaviours.
     */
    sf.logger.addCase('warning', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.WARN, 'warning', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    sf.logger.alias('warn', 'warning');

    /**
     * Adding case for logging general info about the system working.
     */
    sf.logger.addCase('info', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.INFO, 'info', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging system level debug messages.
     */
    sf.logger.addCase('debug', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.DEBUG, 'debug', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging local node/service debug messages.
     */
    sf.logger.addCase('ldebug', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.LOCAL_DEBUG, 'ldebug', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging user level debug messages.
     */
    sf.logger.addCase('udebug', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.USER_DEBUG, 'udebug', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging development debug messages.
     */
    sf.logger.addCase('devel', function (message) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.DEV_DEBUG, 'devel', message, null, false, arguments, 0));
    }, [
        {
            'message': 'explanation'
        }
    ]);

    /**
     * Adding case for logging "whys" reasoning messages.
     */
    sf.logger.addCase("logWhy", function (logOnlyCurrentWhyContext) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.WHYS, 'logwhy', undefined, undefined, undefined, undefined, undefined, undefined, logOnlyCurrentWhyContext));
    });

    /**
     * Adding case for logging asserts messages to running tests.
     */
    sf.logger.addCase("recordAssert", function (message, error, showStack) {
        sf.logger.record(createDebugRecord(LOG_LEVELS.TEST_RESULT, 'assert', message, error, showStack));
    });

    /**
     * Generic method to create structured debug records based on the log level.
     * @param level {Number} - number from 1-11, used to identify the level of attention that a log entry should get from operations point of view
     * @param type {String} - identifier name for log type
     * @param message {String} - description of the debug record
     * @param exception {String} - exception details if any
     * @param saveStack {Boolean} - if set to true, the exception call stack will be added to the debug record
     * @param args {Array} - arguments of the caller function
     * @param pos {Number} - position
     * @param data {String|Number|Array|Object} - payload information
     * @param logOnlyCurrentWhyContext - if whys is enabled, only the current context will be logged
     * @returns Debug record model {Object} with the following fields:
     * [required]: level: *, type: *, timestamp: number, message: *, data: * and
     * [optional]: stack: *, exception: *, args: *, whyLog: *
     */
    function createDebugRecord(level, type, message, exception, saveStack, args, pos, data, logOnlyCurrentWhyContext) {

        var ret = {
            level: level,
            type: type,
            timestamp: (new Date()).getTime(),
            message: message
        };

        if(data){
            ret.data = data;
        }

        if (saveStack) {
            var stack = '';
            if (exception) {
                stack = exception.stack;
            } else {
                stack = (new Error()).stack;
            }
            ret.stack = stack;
        }

        if (exception) {
            ret.exception = exception.message;
        }

        if (args) {
            ret.args = JSON.parse(JSON.stringify(args));
        }

        if (process.env.RUN_WITH_WHYS) {
            var why = require('whys');
            if (logOnlyCurrentWhyContext) {
                ret['whyLog'] = why.getGlobalCurrentContext().getExecutionSummary();
            } else {
                ret['whyLog'] = why.getAllContexts().map(function (context) {
                    return context.getExecutionSummary();
                });
            }
        }
        return ret;
    }

}
;

<|endoftext|>


<commit_before>'use strict';

module.exports = async (documentId, dbManager) => {
	const instance = {};

	instance.documentId = documentId;
	instance.dbManager = dbManager;

	instance.isHasPermission = async (permissionName) => {
		const app = await dbManager.findArrayAsync('applications', {_id: documentId})[0];

		if (app == undefined)
			throw new Error('application not found');

		return permissionName in app.permissions;
	};

	instance.generateApplicationKey = async () => {
		// TODO
	};

	instance.getApplicationKey = async () => {
		// TODO
	};

	return instance;
};
<commit_msg>implement application document-model<commit_after>'use strict';

const applicationHelper = require('../modules/application-helper');
const randomRange = require('../modules/random-range');

module.exports = async (documentId, dbManager) => {
	const instance = {};

	instance.isHasPermission = async (permissionName) => {
		const app = await dbManager.findArrayAsync('applications', {_id: documentId})[0];

		if (app == undefined)
			throw new Error('application not found');

		return permissionName in app.permissions;
	};

	instance.generateApplicationKey = async () => {
		const keyCode = randomRange(1, 99999);
		dbManager.updateAsync('applications', {_id: documentId}, {key_code: keyCode});
		const app = await dbManager.findArrayAsync('applications', {_id: documentId})[0];

		return applicationHelper.buildApplicationKey(app._id, app.creator_id, app.key_code);
	};

	instance.getApplicationKey = async () => {
		const app = await dbManager.findArrayAsync('applications', {_id: documentId})[0];

		if (app == undefined)
			throw new Error('application not found');

		return applicationHelper.buildApplicationKey(app._id, app.creator_id, app.key_code);
	};

	return instance;
};
<|endoftext|>


<commit_before>var webdriver = require('selenium-webdriver'),
    chrome = require('selenium-webdriver/chrome'),
    By = webdriver.By,
    until = webdriver.until,
    test = require('selenium-webdriver/testing');

test.describe('Простой тест для логина и пароля', function() {
    var driver;

    test.before(function() {
        driver = new webdriver.Builder()
            .forBrowser('chrome')
            .build();
        driver.getCapabilities().then(function(caps) {
            console.log(caps);
        });
    });

    test.it('Должен работать вход под админом', function() {
        driver.get('http://localhost/litecart/admin/');
        driver.findElement(By.name('username')).sendKeys('admin');
        driver.findElement(By.name('password')).sendKeys('admin');
        driver.findElement(By.name('login')).click();
    });

    test.after(function() {
        driver.quit();
    });
});<commit_msg>добавил проверку тайтла<commit_after>var webdriver = require('selenium-webdriver'),
    chrome = require('selenium-webdriver/chrome'),
    By = webdriver.By,
    until = webdriver.until,
    test = require('selenium-webdriver/testing');

test.describe('Простой тест для логина и пароля', function() {
    var driver;

    test.before(function() {
        driver = new webdriver.Builder()
            .forBrowser('chrome')
            .build();
        driver.getCapabilities().then(function(caps) {
            console.log(caps);
        });
    });

    test.it('Должен работать вход под админом', function() {
        driver.get('http://localhost/litecart/admin/');
        driver.findElement(By.name('username')).sendKeys('admin');
        driver.findElement(By.name('password')).sendKeys('admin');
        driver.findElement(By.name('login')).click();
        driver.wait(until.titleIs('My Store'), 3000);
    });

    test.after(function() {
        driver.quit();
    });
});<|endoftext|>


<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 *
 *
 * TODO :
 *     - files extensions matching optimisation
 *     - add optimised mode that do not return deep chain handle for any HTTP verb (to be used when stores are used from within a chain)
 *     - check range object usage in chain
 *
 *
 *
 * - CLONE STORES : reset and initialised = false
 */

if (typeof define !== 'function') {
    var define = require('amdefine')(module);
}

define(["require", "../utils", "../errors", "../promise", "../compiler"], function(require, utils, errors, prom) {

    var argToArr = Array.prototype.slice;
    var stores = {};
    //deep.extensions = [];
    /**
     * start chain setted with a certain store
     * @example
     *
     * Store("json").get("/campaign/").log();

     *  ...
     *  Store("campaign").get("?").log()
     *
     *
     * @class Store
     * @constructor
     */
    stores.store = function(store) {
        //console.log("Store(name) : ", name)
        return deep(store || {})
        .done(function(){
            if(!this._storeDef)
                this.store(store);
        })
        .done(function(s) {
            //console.log("store init trough chain : ", handler.provider);
            this._nodes = [deep.nodes.root(s)];
        });
    };

    stores.store.prepare = function(store)
    {
        if(typeof store === 'string')
            store = deep.protocol(store);
        if(!store)
            return errors.Store("no store found with : ",store);
        //console.log("PREPARE CONTEXT --------> ", deep.context.modes);
        if(store._deep_ocm_)
            return store.flatten()
            .done(function(store){
            	//console.log("Store prepare OCM flattened : ", deep.context.modes, store());
                store = store();
                if(store.init)
                    return store.init() || store;
            });
        if(store.init)
            return store.init() || store;
        return store;
    }

    /**
     * Empty class : Just there to get instanceof working (be warning with iframe issue in that cases).
     * @class Store
     * @constructor
     */
    var Store = stores.Store = function(protocol) {
        //console.log("Store : protocol : ", protocol);
        if (protocol && typeof protocol === 'object')
            utils.up(protocol, this);
        else
            this.protocol = protocol || this.protocol;

        if (this.protocol)
            deep.protocol(this.protocol, this);
        this._deep_store_ = true;
    };

    Store.prototype = {
        _deep_restrictable_:["get","range","post","put","patch","del","rpc","bulk"]
    };

    stores.Store.forbidden = function(message) {
        return function(any, options) {
            return errors.Forbidden(message);
        };
    };
    stores.store.Restrictions = function() {
        var restrictions = {};
        for (var i in arguments)
            restrictions[arguments[i]] = Store.forbidden();
        return restrictions;
    };
    stores.store.AllowOnly = function() {
        var allowable = argToArr.call(arguments);
        var restrictions = {
            inner:{},
            allowable:allowable,
            _deep_compiler_ : true,
            _deep_allow_only_ : true,
            up : function() {                 // apply arguments (up) on inner-layer : so merge
                // console.log("allow only up : ", arguments);
                var res = this.inner;
                for (var i = 0, len = arguments.length; i < len; ++i)
                {
                    var argi = arguments[i];
                    if(argi._deep_allow_only_)
                    {
                        res = utils.up(argi.inner, res);
                        this.allowable = utils.up(argi.allowable, this.allowable);
                    }
                    else
                        res = utils.up(argi, res);
                }
                this.inner = res;
                return this;
            },
            bottom : function() {             // apply arguments (bottom) on this : so apply restrictions

                // console.log("allow only bottom : ", arguments);
                var res = this.inner, toKeep = null;
                for (var len = arguments.length-1; len >= 0; --len)
                {
                    var argi = arguments[len];
                    if(argi._deep_allow_only_)
                    {
                        res = utils.bottom(argi.inner, res);
                        this.allowable = utils.up(argi.allowable, this.allowable);
                    }
                    else
                        res = utils.bottom(argi, res);
                }
                if(res._deep_restrictable_)
                {
                    var toRemove = deep.utils.removeInside(res._deep_restrictable_.slice(), allowable);
                    for(var j = 0, lenj = toRemove.length; j < lenj; ++j)
                        res[toRemove[j]] = Store.forbidden();
                }
                else
                {
                    if(!toKeep)
                    {
                        toKeep = {};
                        for(var l = 0, lenl = allowable.length; l < lenl; ++l)
                            toKeep[allowable[l]] = true;
                    }
                    for(var k in res)
                        if(!toKeep[k])
                            res[k] = Store.forbidden();
                }
                // console.log("allow only bottom : res :  ", res);
                return res;
            }
        };
        return restrictions;
    };

    stores.store.filterPrivate = function(method) {
        return function(result) {
            //console.log("private check : ", this, result);
            if (!this.schema)
                return result;
            var schema = this.schema;
            if (schema._deep_ocm_)
                schema = schema(method);
            var res = utils.remove(result, ".//!?_schema.private=true", this.schema);
            return result;
        };
    };

    return stores;
});

<commit_msg>clean<commit_after>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 *
 *
 * TODO :
 *     - files extensions matching optimisation
 *     - add optimised mode that do not return deep chain handle for any HTTP verb (to be used when stores are used from within a chain)
 *     - check range object usage in chain
 *
 *
 *
 * - CLONE STORES : reset and initialised = false
 */

if (typeof define !== 'function') {
    var define = require('amdefine')(module);
}

define(["require", "../utils", "../errors", "../promise", "../compiler"], function(require, utils, errors, prom) {

    var argToArr = Array.prototype.slice;
    var stores = {};
    //deep.extensions = [];
    /**
     * start chain setted with a certain store
     * @example
     *
     * Store("json").get("/campaign/").log();

     *  ...
     *  Store("campaign").get("?").log()
     *
     *
     * @class Store
     * @constructor
     */
    stores.store = function(store) {
        //console.log("Store(name) : ", name)
        return deep(store || {})
        .done(function(){
            if(!this._storeDef)
                this.store(store);
        })
        .done(function(s) {
            //console.log("store init trough chain : ", handler.provider);
            this._nodes = [deep.nodes.root(s)];
        });
    };

    stores.store.prepare = function(store)
    {
        if(typeof store === 'string')
            store = deep.protocol(store);
        if(!store)
            return errors.Store("no store found with : ",store);
        //console.log("PREPARE CONTEXT --------> ", deep.context.modes);
        if(store._deep_ocm_)
            return store.flatten()
            .done(function(store){
            	//console.log("Store prepare OCM flattened : ", deep.context.modes, store());
                store = store();
                if(store.init)
                    return store.init() || store;
            });
        if(store.init)
            return store.init() || store;
        return store;
    }

    /**
     * Empty class : Just there to get instanceof working (be warning with iframe issue in that cases).
     * @class Store
     * @constructor
     */
    var Store = stores.Store = function(protocol) {
        //console.log("Store : protocol : ", protocol);
        if (protocol && typeof protocol === 'object')
            utils.up(protocol, this);
        else
            this.protocol = protocol || this.protocol;

        if (this.protocol)
            deep.protocol(this.protocol, this);
        this._deep_store_ = true;
    };

    Store.prototype = {
        _deep_restrictable_:["get","range","post","put","patch","del","rpc","bulk"]
    };

    stores.Store.forbidden = function(message) {
        return function(any, options) {
            return errors.Forbidden(message);
        };
    };
    stores.store.Restrictions = function() {
        var restrictions = {};
        for (var i in arguments)
            restrictions[arguments[i]] = Store.forbidden();
        return restrictions;
    };
    stores.store.AllowOnly = function() {
        return {
            inner:{},
            allowable:argToArr.call(arguments),
            _deep_compiler_ : true,
            _deep_allow_only_ : true,
            up : function() {                 // apply arguments (up) on inner-layer : so merge
                // console.log("allow only up : ", arguments);
                var res = this.inner;
                for (var i = 0, len = arguments.length; i < len; ++i)
                {
                    var argi = arguments[i];
                    if(argi._deep_allow_only_)
                    {
                        res = utils.up(argi.inner, res);
                        this.allowable = utils.up(argi.allowable, this.allowable);
                    }
                    else
                        res = utils.up(argi, res);
                }
                this.inner = res;
                return this;
            },
            bottom : function() {             // apply arguments (bottom) on this : so apply restrictions

                // console.log("allow only bottom : ", arguments);
                var res = this.inner, toKeep = null;
                for (var len = arguments.length-1; len >= 0; --len)
                {
                    var argi = arguments[len];
                    if(argi._deep_allow_only_)
                    {
                        res = utils.bottom(argi.inner, res);
                        this.allowable = utils.up(argi.allowable, this.allowable);
                    }
                    else
                        res = utils.bottom(argi, res);
                }
                if(res._deep_restrictable_)
                {
                    var toRemove = deep.utils.removeInside(res._deep_restrictable_.slice(), this.allowable);
                    for(var j = 0, lenj = toRemove.length; j < lenj; ++j)
                        res[toRemove[j]] = Store.forbidden();
                }
                else
                {
                    if(!toKeep)
                    {
                        toKeep = {};
                        for(var l = 0, lenl = this.allowable.length; l < lenl; ++l)
                            toKeep[this.allowable[l]] = true;
                    }
                    for(var k in res)
                        if(!toKeep[k])
                            res[k] = Store.forbidden();
                }
                // console.log("allow only bottom : res :  ", res);
                return res;
            }
        };
    };

    stores.store.filterPrivate = function(method) {
        return function(result) {
            //console.log("private check : ", this, result);
            if (!this.schema)
                return result;
            var schema = this.schema;
            if (schema._deep_ocm_)
                schema = schema(method);
            var res = utils.remove(result, ".//!?_schema.private=true", this.schema);
            return result;
        };
    };

    return stores;
});

<|endoftext|>


<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 *
 *
 * TODO :
 *     - files extensions matching optimisation
 *     - add optimised mode that do not return deep chain handle for any HTTP verb (to be used when stores are used from within a chain)
 *     - check range object usage in chain
 *
 *
 *
 * - CLONE STORES : reset and initialised = false
 */

if (typeof define !== 'function') {
	var define = require('amdefine')(module);
}

define(["require"], function (require) {

	return function(deep){

		deep.extensions = [];
		deep.clients = deep.client || {};
		/**
		 * start chain setted with a certain store
		 * @example
		 *
		 * deep.store("json").get("/campaign/").log();

		 *  ...
		 *  deep.store("campaign").get("?").log()
		 *
		 *
		 * @class deep.store
		 * @constructor
		 */
		deep.store = function (name) {
			//console.log("deep.store(name) : ",name)
			return deep(deep.protocol.parse(name).done(function(handler){ return handler.provider; }))//, { ignoreInit:true, ignoreOCM:true}))
			.store(name);
		};

		/**
		 * Empty class : Just there to get instanceof working (be warning with iframe issue in that cases).
		 * @class deep.Store
		 * @constructor
		 */
		deep.Store = function (protocol) {
			//console.log("deep.Store : protocol : ", protocol);
			if(protocol && typeof protocol === 'object')
				deep.utils.up(protocol, this);
			else
				this.protocol = protocol || this.protocol;

			if (this.protocol)
				deep.protocol(this.protocol, this);
			this._deep_store_ = true;
		};

		deep.Store.forbidden = function(message){
			return function(any, options)
			{
				return deep.when(deep.errors.Forbidden(message));
			};
		};
		deep.store.Restrictions = function()
		{
			var restrictions = {};
			for(var i in arguments)
				restrictions[arguments[i]] = deep.Store.forbidden();
			return restrictions;
		};
		deep.store.AllowOnly = function()
		{
			var restrictions = {
				get:deep.Store.forbidden(),
				range:deep.Store.forbidden(),
				post:deep.Store.forbidden(),
				put:deep.Store.forbidden(),
				patch:deep.Store.forbidden(),
				del:deep.Store.forbidden(),
				rpc:deep.Store.forbidden(),
				bulk:deep.Store.forbidden()
			};
			for(var i in arguments)
				delete restrictions[arguments[i]];
			return restrictions;
		};

		deep.store.filterPrivate = function(method)
		{
			return function(result){
				//console.log("private check : ", this, result);
				if(!this.schema)
					return result;
				var schema = this.schema;
				if(schema._deep_ocm_)
					schema = schema(method);
				var res = deep.utils.remove(result, ".//!?_schema.private=true", this.schema);
				return result;
			};
		};

		return deep;
	};
});

<commit_msg>comment deep.extensions<commit_after>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 *
 *
 * TODO :
 *     - files extensions matching optimisation
 *     - add optimised mode that do not return deep chain handle for any HTTP verb (to be used when stores are used from within a chain)
 *     - check range object usage in chain
 *
 *
 *
 * - CLONE STORES : reset and initialised = false
 */

if (typeof define !== 'function') {
	var define = require('amdefine')(module);
}

define(["require"], function (require) {

	return function(deep){

		//deep.extensions = [];
		deep.clients = deep.client || {};
		/**
		 * start chain setted with a certain store
		 * @example
		 *
		 * deep.store("json").get("/campaign/").log();

		 *  ...
		 *  deep.store("campaign").get("?").log()
		 *
		 *
		 * @class deep.store
		 * @constructor
		 */
		deep.store = function (name) {
			//console.log("deep.store(name) : ",name)
			return deep(deep.protocol.parse(name).done(function(handler){ return handler.provider; }))//, { ignoreInit:true, ignoreOCM:true}))
			.store(name);
		};

		/**
		 * Empty class : Just there to get instanceof working (be warning with iframe issue in that cases).
		 * @class deep.Store
		 * @constructor
		 */
		deep.Store = function (protocol) {
			//console.log("deep.Store : protocol : ", protocol);
			if(protocol && typeof protocol === 'object')
				deep.utils.up(protocol, this);
			else
				this.protocol = protocol || this.protocol;

			if (this.protocol)
				deep.protocol(this.protocol, this);
			this._deep_store_ = true;
		};

		deep.Store.forbidden = function(message){
			return function(any, options)
			{
				return deep.when(deep.errors.Forbidden(message));
			};
		};
		deep.store.Restrictions = function()
		{
			var restrictions = {};
			for(var i in arguments)
				restrictions[arguments[i]] = deep.Store.forbidden();
			return restrictions;
		};
		deep.store.AllowOnly = function()
		{
			var restrictions = {
				get:deep.Store.forbidden(),
				range:deep.Store.forbidden(),
				post:deep.Store.forbidden(),
				put:deep.Store.forbidden(),
				patch:deep.Store.forbidden(),
				del:deep.Store.forbidden(),
				rpc:deep.Store.forbidden(),
				bulk:deep.Store.forbidden()
			};
			for(var i in arguments)
				delete restrictions[arguments[i]];
			return restrictions;
		};

		deep.store.filterPrivate = function(method)
		{
			return function(result){
				//console.log("private check : ", this, result);
				if(!this.schema)
					return result;
				var schema = this.schema;
				if(schema._deep_ocm_)
					schema = schema(method);
				var res = deep.utils.remove(result, ".//!?_schema.private=true", this.schema);
				return result;
			};
		};

		return deep;
	};
});

<|endoftext|>


<commit_before>(function (root) {
    var Streaming = {
        subscriptions: {},
        callbacks: {},
    };

    Streaming.NullDbDriver = function () {
        this.initialize = function initialize() {
            return new Promise(function (resolve) {
                resolve();
            });
        };

        /**
         *
         * @param url - What to retrieve from the database
         * @returns {Promise}
         *
         * Promise resolves into the following structure:
         * {
             *  data: data
             *  revision: what revision the data is
             *  hash: Hash of the data for comparison
             *  expire: when the data expires
             *  user_id: who stored the data
             * }
         *
         */
        this.get = function (url) {
            return new Promise(function get(resolve, reject) {
                reject(new Error("No driver configured"));
            });
        };

        /**
         *
         * @param url - What to store
         * @param data - Data to store
         * @param meta - Metadata describing the data
         * @returns {Promise}
         *
         * Meta structure should look as follows:
         * {
             *  revision: Revision of the currently retrieved data (undefined if none has been previously been retrieved)
             *  hash: Hash of the data
             *  expire: When the data should expire
             *  user_id: User id of whoever is storing the data
             * }
         *
         * Promise resolves into the revision of the updated data
         */
        this.put = function (url, data, meta) {
            return new Promise(function put(resolve, reject) {
                reject(new Error("No driver configured"));
            });
        };
    };

    Streaming.setUser = function setUser(user_id) {
        this.user_id = user_id;
    };

    Streaming.setup = function setup(socket, options) {
        options = options || {};

        _.defaults(options, {
            expire: 2 * 60 * 60 * 1000
        });

        this.socket = socket;
        this.options = options;

        this.user_id = 0;
        this.db = new (options.db ? options.db : this.NullDbDriver)();

        this.db.initialize().then(function () {}, function (err) {
            console.error("Failed to initialize DB driver", err);
        });

        socket.on('connect', _.bind(function() {
            this.onConnect(socket);
        }, this));

        socket.on('disconnect', _.bind(function () {
            this.onDisconnect();
        }, this));

        socket.on('stream', _.bind(function (message) {
            this.sync(message);
        }, this));
    };

    Streaming.sync = function sync(message) {
        var item = this.subscriptions[message.url];
        if (!item) {
            return;
        }

        this.db.put(message.url, message.data, {
            revision: item.revision,
            hash: message.hash,
            user_id: this.user_id,
            expire: new Date(new Date().getTime() + this.options.expire)
        }).then(function (revision) {
            item.revision = revision;
        });

        var data = item.cache = this.uncompress(message.data);
        try {
            this.apply(data, item.clients);
        } catch (e) {
            console.error(e.stack ? e.stack : e.message);
        }
    };

    Streaming.apply = function apply(data, items) {
        _.each(items, function (model) {
            if (!model.streaming) {
                return;
            }

            var initial = model.streaming.options.initial;
            model.streaming.options.initial = false;

            data = model.parse(data);

            if (model.models.length > 0) {
                var idAttribute = model.models[0].idAttribute;
                var equals = false;
                do {
                    if (initial === true) {
                        break;
                    }

                    if (model.models.length != data.length) {
                        break;
                    }

                    var local = _.pluck(model.models, "id");
                    var remote = _.pluck(data, idAttribute)

                    var i = 0, n = model.models.length;
                    for (;i !=n; ++i) {
                        if (local[i] != remote[i]) {
                            break;
                        }
                    }
                    if (i != n) {
                        break;
                    }
                    equals = true;
                } while (0);
                if (equals) {
                    model.forEach(function (current, index) {
                        current.set(current.parse(data[index]));
                    });
                    model.trigger('sync', model, data, {});
                } else {
                    model.reset(data);
                }

            } else {
                model.reset(data);
            }
        });
    };

    Streaming.emit = function emit(url, item) {
        item.updating = true;

        var message = {
            url: url
        };

        this.db.get(url)
            .then(_.bind(function (doc) {
                item.revision = doc.revision;

                if ((doc.user_id == this.user_id) && item.options.precache) {
                    message.hash = doc.hash;
                    item.cache = this.uncompress(doc.data);
                }

                try {
                    this.apply(item.cache, item.clients);
                } catch (e) {
                    console.error(e.stack ? e.stack : e.message);
                }

                return doc;
            }, this), function (err) {
                console.error(url, err);
            })
            .then(_.bind(function (doc) {
                this.send("stream", message, _.bind(function (err, response) {
                    delete item.updating;

                    if (err) {
                        return;
                    }

                    var uncompressed;
                    if (response.hash == message.hash) {
                        var limit = Date.now() + this.options.expire / 2;
                        if (doc.expire < limit || (doc.user_id != this.user_id)) {
                            this.db.put(message.url, doc.data, {
                                revision: item.revision,
                                hash: message.hash,
                                user_id: this.user_id,
                                expire: Date.now() + this.options.expire
                            }).then(function (revision) {
                                item.revision = revision;
                            }, function (err) {
                                console.error(err);
                            });
                        }

                        if (!item.cache) {
                            item.cache = uncompressed = this.uncompress(doc.data);
                        }
                    } else {
                        this.db.put(message.url, response.data, {
                            revision: item.revision,
                            hash: response.hash,
                            user_id: this.user_id,
                            expire: Date.now() + this.options.expire
                        }).then(function (revision) {
                            item.revision = revision;
                        }, function (err) {
                            console.error(err);
                        });

                        item.cache = uncompressed = this.uncompress(response.data);
                    }

                    if (uncompressed) {
                        try {
                            this.apply(uncompressed, item.clients);
                        } catch (e) {
                            console.error(e.stack ? e.stack : e.message);
                        }
                    }
                }, this));
            }, this));
    };

    Streaming.onConnect = function onConnect(socket) {
        this.socket = socket;

        _.each(this.subscriptions, function (item, url) {
            this.emit(url, item);
        }, this);
    };

    Streaming.onDisconnect = function onDisconnect() {
        _.each(this.subscriptions, function (item) {
            delete item.cache;
            if (item.timeout) {
                clearTimeout(item.timeout);
                delete item.timeout;
            }
        });

        _.each(this.callbacks, function (callback, id) {
            callback("Disconnected");
        });
        this.callbacks = {};

        delete this.socket;
    };

    Streaming.add = function add(target, options) {
        var url = target.url();
        if (target.streaming) {
            return;
        }

        options = options ? _.clone(options) : {};
        _.defaults(options, {
            "precache": !!target.precache,
            "initial": true
        });

        var item = this.subscriptions[url];
        if (!_.isUndefined(item)) {
            if (item.timeout) {
                clearTimeout(item.timeout);
                delete item.timeout;
            }

            target.streaming = { url: url, options: options };
            item.clients[target.cid] = target;

            if (item.cache) {
                try {
                    this.apply(item.cache, [target]);
                } catch (e) {
                    console.error(e.stack ? e.stack : e.message);
                }
            }
            return;
        } else {
            item = { clients: {}, options: options };
            item.clients[target.cid] = target;

            target.streaming = { url: url, options: options };
            this.subscriptions[url] = item;
        }

        if (_.isUndefined(this.socket)) {
            return;
        }

        this.emit(url, item);
    };

    Streaming.remove = function remove(target) {
        if (target.streaming) {
            var url = target.streaming.url;
            var item = this.subscriptions[url];

            delete item.clients[target.cid];
            if (_.keys(item.clients).length == 0) {
                item.timeout = setTimeout(_.bind(function () {
                    this.socket.emit("unstream", { url: url }, function (err) {});
                    delete this.subscriptions[url];
                }, this), 5000);
            }

            delete target.streaming;
        }
    };

    Streaming.send = function send(type, message, callback) {
        if (!this.socket) {
            _.defer(function () {
                callback("No connection");
            });
            return;
        }

        var id = _.uniqueId('cb');
        this.callbacks[id] = callback;

        this.socket.emit(type, message, _.bind(function (err, response) {
            delete this.callbacks[id];
            callback(err, this.uncompress(response));
        }, this));
    };

    Streaming.uncompress = function (data) {
        if (!_.isObject(data)) {
            return data;
        }

        var objectKeys = _.keys(data);

        if ((objectKeys.length != 2) || (_.without(objectKeys, 'keys', 'rows').length != 0)) {
            return data;
        }

        var keys = data.keys;
        var uncompressed = _.map(data.rows, function (row) {
            return _.object(keys, row);
        });

        return uncompressed;
    };

    var sync = function sync(method, model, options) {
        var message = {
            method: method,
            url: model.url(),
            cid: model.cid,
            data: options.arguments || model.toJSON() || {},
            emit: options.emit
        };

        Streaming.send("sync", message, function (err, response) {
            if (err) {
                options.error(err);
            } else {
                options.success(response);
            }
        });
    };

    Streaming.Model = Backbone.Model.extend({
        stream: function stream() {
            console.trace();
            alert("Streaming models is not currently supported");
        },

        unstream: function unstream() {},

        incrementVersion: function incrementVersion() {
            var versionName = this.versionAttribute;
            if (!_.isUndefined(versionName)) {
                this.set(versionName, this.parseVersionNumber(this.get(versionName)) + 1, {silent: true});
            }
        },

        parseVersionNumber: function parseVersionNumber(versionNumber) {
            return _.isFinite(versionNumber) ? versionNumber : 0;
        },

        parse: function parse(resp) {
            var versionName = this.versionAttribute;
            if (_.isObject(resp) && !_.isUndefined(versionName)) {
                var localVersion = this.parseVersionNumber(this.get(versionName));
                var remoteVersion = this.parseVersionNumber(resp[versionName]);

                if (localVersion > remoteVersion) {
                    return {};
                }
            }
            return resp;
        },

        emit: function emit(method, args, options) {
            if (_.isUndefined(options)) {
                options = args ? _.clone(args) : {};
                args = undefined;
            } else {
                options = options ? _.clone(options) : {};
            }

            var model = this;

            var triggerEmit = _.bind(function() {
                model.trigger('emit emit:' + method, model, options);
            }, this);

            options.emit = method;
            options.arguments = args;

            var success = options.success;
            options.success = function onSuccess(resp) {
                if (success) success(model, resp, options);
                if (options.wait) triggerEmit();
            };
            var error = options.error;
            options.error = function onError(resp) {
                if (error) error(model, resp, options);
                model.trigger('error', model, resp, options);
            };

            var xhr = this.sync('emit', this, options);
            if (!options.wait) triggerEmit();
            return xhr;
        },

        sync: sync
    });

    Streaming.Collection = Backbone.Collection.extend({
        stream: function stream(options) {
            options = options || {};
            if (_.isUndefined(this.cid)) {
                this.cid = _.uniqueId('coll');
            }

            _.defer(_.bind(function () {
                Streaming.add(this, options);
            }, this));
        },

        unstream: function unstream() {
            Streaming.remove(this);
        },

        emit: function emit(method, args, options) {
            if (_.isUndefined(options)) {
                options = args ? _.clone(args) : {};
                args = undefined;
            } else {
                options = options ? _.clone(options) : {};
            }

            var model = this;

            var triggerEmit = _.bind(function emit() {
                model.trigger('emit emit:' + method, model, options);
            }, this);

            options.emit = method;
            options.arguments = args;

            var success = options.success;
            options.success = function onSuccess(resp) {
                if (success) success(model, resp, options);
                if (options.wait) triggerEmit();
            };
            var error = options.error;
            options.error = function onError(resp) {
                if (error) error(model, resp, options);
                model.trigger('error', model, resp, options);
            };

            var xhr = this.sync('emit', this, options);
            if (!options.wait) triggerEmit();
            return xhr;
        },

        sync: sync
    });

    root.Streaming = Streaming;
})(this);

<commit_msg>Removed debug output for db gets<commit_after>(function (root) {
    var Streaming = {
        subscriptions: {},
        callbacks: {},
    };

    Streaming.NullDbDriver = function () {
        this.initialize = function initialize() {
            return new Promise(function (resolve) {
                resolve();
            });
        };

        /**
         *
         * @param url - What to retrieve from the database
         * @returns {Promise}
         *
         * Promise resolves into the following structure:
         * {
             *  data: data
             *  revision: what revision the data is
             *  hash: Hash of the data for comparison
             *  expire: when the data expires
             *  user_id: who stored the data
             * }
         *
         */
        this.get = function (url) {
            return new Promise(function get(resolve, reject) {
                reject(new Error("No driver configured"));
            });
        };

        /**
         *
         * @param url - What to store
         * @param data - Data to store
         * @param meta - Metadata describing the data
         * @returns {Promise}
         *
         * Meta structure should look as follows:
         * {
             *  revision: Revision of the currently retrieved data (undefined if none has been previously been retrieved)
             *  hash: Hash of the data
             *  expire: When the data should expire
             *  user_id: User id of whoever is storing the data
             * }
         *
         * Promise resolves into the revision of the updated data
         */
        this.put = function (url, data, meta) {
            return new Promise(function put(resolve, reject) {
                reject(new Error("No driver configured"));
            });
        };
    };

    Streaming.setUser = function setUser(user_id) {
        this.user_id = user_id;
    };

    Streaming.setup = function setup(socket, options) {
        options = options || {};

        _.defaults(options, {
            expire: 2 * 60 * 60 * 1000
        });

        this.socket = socket;
        this.options = options;

        this.user_id = 0;
        this.db = new (options.db ? options.db : this.NullDbDriver)();

        this.db.initialize().then(function () {}, function (err) {
            console.error("Failed to initialize DB driver", err);
        });

        socket.on('connect', _.bind(function() {
            this.onConnect(socket);
        }, this));

        socket.on('disconnect', _.bind(function () {
            this.onDisconnect();
        }, this));

        socket.on('stream', _.bind(function (message) {
            this.sync(message);
        }, this));
    };

    Streaming.sync = function sync(message) {
        var item = this.subscriptions[message.url];
        if (!item) {
            return;
        }

        this.db.put(message.url, message.data, {
            revision: item.revision,
            hash: message.hash,
            user_id: this.user_id,
            expire: new Date(new Date().getTime() + this.options.expire)
        }).then(function (revision) {
            item.revision = revision;
        });

        var data = item.cache = this.uncompress(message.data);
        try {
            this.apply(data, item.clients);
        } catch (e) {
            console.error(e.stack ? e.stack : e.message);
        }
    };

    Streaming.apply = function apply(data, items) {
        _.each(items, function (model) {
            if (!model.streaming) {
                return;
            }

            var initial = model.streaming.options.initial;
            model.streaming.options.initial = false;

            data = model.parse(data);

            if (model.models.length > 0) {
                var idAttribute = model.models[0].idAttribute;
                var equals = false;
                do {
                    if (initial === true) {
                        break;
                    }

                    if (model.models.length != data.length) {
                        break;
                    }

                    var local = _.pluck(model.models, "id");
                    var remote = _.pluck(data, idAttribute)

                    var i = 0, n = model.models.length;
                    for (;i !=n; ++i) {
                        if (local[i] != remote[i]) {
                            break;
                        }
                    }
                    if (i != n) {
                        break;
                    }
                    equals = true;
                } while (0);
                if (equals) {
                    model.forEach(function (current, index) {
                        current.set(current.parse(data[index]));
                    });
                    model.trigger('sync', model, data, {});
                } else {
                    model.reset(data);
                }

            } else {
                model.reset(data);
            }
        });
    };

    Streaming.emit = function emit(url, item) {
        item.updating = true;

        var message = {
            url: url
        };

        this.db.get(url)
            .then(_.bind(function (doc) {
                item.revision = doc.revision;

                if ((doc.user_id == this.user_id) && item.options.precache) {
                    message.hash = doc.hash;
                    item.cache = this.uncompress(doc.data);
                }

                try {
                    this.apply(item.cache, item.clients);
                } catch (e) {
                    console.error(e.stack ? e.stack : e.message);
                }

                return doc;
            }, this), function (err) {})
            .then(_.bind(function (doc) {
                this.send("stream", message, _.bind(function (err, response) {
                    delete item.updating;

                    if (err) {
                        return;
                    }

                    var uncompressed;
                    if (response.hash == message.hash) {
                        var limit = Date.now() + this.options.expire / 2;
                        if (doc.expire < limit || (doc.user_id != this.user_id)) {
                            this.db.put(message.url, doc.data, {
                                revision: item.revision,
                                hash: message.hash,
                                user_id: this.user_id,
                                expire: Date.now() + this.options.expire
                            }).then(function (revision) {
                                item.revision = revision;
                            }, function (err) {
                                console.error(err);
                            });
                        }

                        if (!item.cache) {
                            item.cache = uncompressed = this.uncompress(doc.data);
                        }
                    } else {
                        this.db.put(message.url, response.data, {
                            revision: item.revision,
                            hash: response.hash,
                            user_id: this.user_id,
                            expire: Date.now() + this.options.expire
                        }).then(function (revision) {
                            item.revision = revision;
                        }, function (err) {
                            console.error(err);
                        });

                        item.cache = uncompressed = this.uncompress(response.data);
                    }

                    if (uncompressed) {
                        try {
                            this.apply(uncompressed, item.clients);
                        } catch (e) {
                            console.error(e.stack ? e.stack : e.message);
                        }
                    }
                }, this));
            }, this));
    };

    Streaming.onConnect = function onConnect(socket) {
        this.socket = socket;

        _.each(this.subscriptions, function (item, url) {
            this.emit(url, item);
        }, this);
    };

    Streaming.onDisconnect = function onDisconnect() {
        _.each(this.subscriptions, function (item) {
            delete item.cache;
            if (item.timeout) {
                clearTimeout(item.timeout);
                delete item.timeout;
            }
        });

        _.each(this.callbacks, function (callback, id) {
            callback("Disconnected");
        });
        this.callbacks = {};

        delete this.socket;
    };

    Streaming.add = function add(target, options) {
        var url = target.url();
        if (target.streaming) {
            return;
        }

        options = options ? _.clone(options) : {};
        _.defaults(options, {
            "precache": !!target.precache,
            "initial": true
        });

        var item = this.subscriptions[url];
        if (!_.isUndefined(item)) {
            if (item.timeout) {
                clearTimeout(item.timeout);
                delete item.timeout;
            }

            target.streaming = { url: url, options: options };
            item.clients[target.cid] = target;

            if (item.cache) {
                try {
                    this.apply(item.cache, [target]);
                } catch (e) {
                    console.error(e.stack ? e.stack : e.message);
                }
            }
            return;
        } else {
            item = { clients: {}, options: options };
            item.clients[target.cid] = target;

            target.streaming = { url: url, options: options };
            this.subscriptions[url] = item;
        }

        if (_.isUndefined(this.socket)) {
            return;
        }

        this.emit(url, item);
    };

    Streaming.remove = function remove(target) {
        if (target.streaming) {
            var url = target.streaming.url;
            var item = this.subscriptions[url];

            delete item.clients[target.cid];
            if (_.keys(item.clients).length == 0) {
                item.timeout = setTimeout(_.bind(function () {
                    this.socket.emit("unstream", { url: url }, function (err) {});
                    delete this.subscriptions[url];
                }, this), 5000);
            }

            delete target.streaming;
        }
    };

    Streaming.send = function send(type, message, callback) {
        if (!this.socket) {
            _.defer(function () {
                callback("No connection");
            });
            return;
        }

        var id = _.uniqueId('cb');
        this.callbacks[id] = callback;

        this.socket.emit(type, message, _.bind(function (err, response) {
            delete this.callbacks[id];
            callback(err, this.uncompress(response));
        }, this));
    };

    Streaming.uncompress = function (data) {
        if (!_.isObject(data)) {
            return data;
        }

        var objectKeys = _.keys(data);

        if ((objectKeys.length != 2) || (_.without(objectKeys, 'keys', 'rows').length != 0)) {
            return data;
        }

        var keys = data.keys;
        var uncompressed = _.map(data.rows, function (row) {
            return _.object(keys, row);
        });

        return uncompressed;
    };

    var sync = function sync(method, model, options) {
        var message = {
            method: method,
            url: model.url(),
            cid: model.cid,
            data: options.arguments || model.toJSON() || {},
            emit: options.emit
        };

        Streaming.send("sync", message, function (err, response) {
            if (err) {
                options.error(err);
            } else {
                options.success(response);
            }
        });
    };

    Streaming.Model = Backbone.Model.extend({
        stream: function stream() {
            console.trace();
            alert("Streaming models is not currently supported");
        },

        unstream: function unstream() {},

        incrementVersion: function incrementVersion() {
            var versionName = this.versionAttribute;
            if (!_.isUndefined(versionName)) {
                this.set(versionName, this.parseVersionNumber(this.get(versionName)) + 1, {silent: true});
            }
        },

        parseVersionNumber: function parseVersionNumber(versionNumber) {
            return _.isFinite(versionNumber) ? versionNumber : 0;
        },

        parse: function parse(resp) {
            var versionName = this.versionAttribute;
            if (_.isObject(resp) && !_.isUndefined(versionName)) {
                var localVersion = this.parseVersionNumber(this.get(versionName));
                var remoteVersion = this.parseVersionNumber(resp[versionName]);

                if (localVersion > remoteVersion) {
                    return {};
                }
            }
            return resp;
        },

        emit: function emit(method, args, options) {
            if (_.isUndefined(options)) {
                options = args ? _.clone(args) : {};
                args = undefined;
            } else {
                options = options ? _.clone(options) : {};
            }

            var model = this;

            var triggerEmit = _.bind(function() {
                model.trigger('emit emit:' + method, model, options);
            }, this);

            options.emit = method;
            options.arguments = args;

            var success = options.success;
            options.success = function onSuccess(resp) {
                if (success) success(model, resp, options);
                if (options.wait) triggerEmit();
            };
            var error = options.error;
            options.error = function onError(resp) {
                if (error) error(model, resp, options);
                model.trigger('error', model, resp, options);
            };

            var xhr = this.sync('emit', this, options);
            if (!options.wait) triggerEmit();
            return xhr;
        },

        sync: sync
    });

    Streaming.Collection = Backbone.Collection.extend({
        stream: function stream(options) {
            options = options || {};
            if (_.isUndefined(this.cid)) {
                this.cid = _.uniqueId('coll');
            }

            _.defer(_.bind(function () {
                Streaming.add(this, options);
            }, this));
        },

        unstream: function unstream() {
            Streaming.remove(this);
        },

        emit: function emit(method, args, options) {
            if (_.isUndefined(options)) {
                options = args ? _.clone(args) : {};
                args = undefined;
            } else {
                options = options ? _.clone(options) : {};
            }

            var model = this;

            var triggerEmit = _.bind(function emit() {
                model.trigger('emit emit:' + method, model, options);
            }, this);

            options.emit = method;
            options.arguments = args;

            var success = options.success;
            options.success = function onSuccess(resp) {
                if (success) success(model, resp, options);
                if (options.wait) triggerEmit();
            };
            var error = options.error;
            options.error = function onError(resp) {
                if (error) error(model, resp, options);
                model.trigger('error', model, resp, options);
            };

            var xhr = this.sync('emit', this, options);
            if (!options.wait) triggerEmit();
            return xhr;
        },

        sync: sync
    });

    root.Streaming = Streaming;
})(this);

<|endoftext|>