<commit_before>//Subclassed Array using Stack
//http://webreflection.blogspot.com/2008/05/habemus-array-unlocked-length-in-ie8.html
STArray = (function(){
    function STArray(){
        this.push.apply(this, Array.apply(null, arguments));
        this.$ = STArray;
    };
    STArray.prototype = new Array;
    STArray.prototype.length = 0;
    if(!new STArray(1).length){
        STArray.prototype = {length:0};
        for(var
            split = "join.pop.push.reverse.shift.slice.sort.splice.unshift".split("."),
            length = split.length;
            length;
        )
            STArray.prototype[split[--length]] = Array.prototype[split[length]];
    };
    var toString= Object.prototype.toString,
        slice   = Array.prototype.slice,
        concat  = Array.prototype.concat
    ;
    STArray.prototype.concat = function(){
        for(var Array = this.slice(0), i = 0, length = arguments.length; i < length; ++i){
            if(toString.call(arguments[i]) != "[object Array]")
                arguments[i] = typeof arguments[i] == "object" ? slice.call(arguments[i]) : [arguments[i]];
        };
        Array.push.apply(Array, concat.apply([], arguments));
        return  Array;
    };
    STArray.prototype.toString = STArray.prototype.join;
    STArray.prototype.constructor = STArray;
    return STArray;
})();

STArray.create = function()
{
    var a = new STArray();
    if (arguments.length) {
        a.append(arguments);
    }
    return a;
};

STArray.createWithArray = function(array)
{
    return new STArray().append(array);
};

if (!STArray.prototype.indexOf) {
    STArray.prototype.indexOf = function(v, n)
    {
        n = (n == null) ? 0 : n;
        var m = this.length;
        for (var i = n; i < m; i++) {
            if (this[i] == v) return i;
        }
        return -1;
    };
}

/**
 * Runs the specified callback function for each item in this array.
 *
 * @param {Function} fun Callback function
 */
STArray.prototype.each = function(fun, object) {
    var fun = ST.P(fun);

    for (var i = 0; i < this.length; i++) {
        if (fun.call(object, this[i], i) == 'break') break;
    }

    return this;
};

/**
 * Removes all items from this array.
 */
STArray.prototype.empty = function()
{
    this.length = 0;
    return this;
};

/**
 * Calls the release method on each item, then removes all items in this Array.
 */
STArray.prototype.releaseAndEmpty = function() {
    this.each('release').length = 0;
    return this;
};

/**
 * Returns true if array is empty (contains no items).
 */
STArray.prototype.isEmpty = function()
{
    return this.length == 0;
};

/**
 * Returns last item in this array, or null if empty.
 */
STArray.prototype.last = function()
{
    if (this.length == 0) return null;
    return this[this.length-1];
};

/**
 * Returns true if array contains the specified item.
 */
STArray.prototype.has = function(object)
{
    return this.indexOf(object) >= 0;
};

/**
 * Returns true if callback function for at least one array member returns
 * true.
 *
 * @param {Function} callback Callback function
 */
STArray.prototype.any = function(fun, object)
{
    var fun = ST.P(fun);

    for (var i = 0; i < this.length; i++) {
        if (fun.call(object, this[i], i)) return true;
    }
    return false;
};

/**
 * Returns true if callback function for every array member returns true.
 *
 * @param {Function} callback Callback function
 */
STArray.prototype.all = function(fun, object)
{
    var fun = ST.P(fun);

    for (var i = 0; i < this.length; i++) {
        if (!fun.call(object, this[i], i)) return false;
    }
    return true;
};

/**
 * Returns a new copy of array with callback function applied to each item.
 */
STArray.prototype.map = function(fun, object)
{
    var fun = ST.P(fun);

    var res = new STArray();
    for (var i = 0; i < this.length; i++) {
        res.push(fun.call(object, this[i], i, this));
    }
    return res;
};

/**
 * Maps all items through a callback function, and returns a standard Array
 * object.
 */
STArray.prototype.mapToStdArray = function(fun, thisp)
{
    var fun = ST.P(fun);

    var res = [];
    for (var i = 0; i < this.length; i++) {
        res.push(fun.call(thisp || null, this[i], i, this));
    }
    return res;
};

/**
 * Creates a copy of array as a standard Array object.
 */
STArray.prototype.toStdArray = function()
{
    var res = [];
    for (var i = 0; i < this.length; i++) {
        res.push(this[i]);
    }
    return res;
};

/**
 * Returns sum of all items.
 */
STArray.prototype.sum = function(initial)
{
    var c = initial || 0;
    for (var i = 0; i < this.length; i++) {
        c += this[i];
    }
    return c;
};

/**
 * Adds items in another array to the end of this one.
 */
STArray.prototype.append = function(array)
{
    this.push.apply(this, array);
    return this;
};

/**
 * Inserts an item at the specified index in Array.
 */
STArray.prototype.insert = function(index, item)
{
    this.splice(index, 0, item);
};

/**
 * Removes the given item from this array, if found,
 */
STArray.prototype.remove = function(object)
{
    for (i = 0; i < this.length; i++) {
        if (this[i] == object) {
            this.splice(i--, 1);
        }
    }
};

/**
 * Removes the item at the given index from this array.
 */
STArray.prototype.removeAtIndex = function(index)
{
    this.splice(index, 1);
};

/**
 * Returns the first item in this array where callback(item) evaluates true
 */
STArray.prototype.find = function(fun, object)
{
    var fun = ST.P(fun);

    for (var i = 0; i < this.length; i++) {
        if (fun.call(object, this[i], i)) return this[i];
    }
    return null;
};

/**
 * Removes all items from this array where callback(item) evaluates to true
 */
STArray.prototype.findRemove = function(fun, object)
{
    var fun = ST.P(fun);

    for (var i = 0; i < this.length; i++) {
        if (fun.call(object, this[i], i)) {
            this.splice(i, 1);
            i--;
        }
    }
    return null;
};

STArray.prototype.findBy = function(key, value) {
    for (var i = 0; i < this.length; i++) {
        if (this[i][key] == value) return this[i];
    }
    return null;
};

/**
 * Removes from array any items with index greater than specified index.
 */
STArray.prototype.trimTo = function(index)
{
    if (this.length > (index + 1)) {
        this.splice(index + 1, this.length - (index+1));
    }
};

/**
 * Returns a new array with the same items as this one (shallow copy).
 */
STArray.prototype.copy = function()
{
    return this.slice();
};

/**
 * Returns a new array containing items within the specified range.
 */
STArray.prototype.slice = function(from, length)
{
    var min = from || 0;
    var max = this.length - 1 - min;
    if (length) max = Math.min(max, min + length - 1);
    var a = STArray.create();
    for (var i = min; i <= max; i++) {
        a.push(this[i]);
    }
    return a;
};

/**
 * Returns a new array with no duplicates.
 */
STArray.prototype.unique = function()
{
    // Build a hash of array items, indexed by unique key
    var h = {};
    for (var i = 0; i < this.length; i++) {
        // Use _uid property as unique key if available, otherwise convert
        // object to string for key.
        h[this[i] && this[i]._uid || this[i]] = this[i];
    }

    // Build new array with now unique items in hash
    var a = new STArray();
    for (i in h) a.push(h[i]);
    return a;
};

/**
 * Returns a new array containing only items where callback returns true
 */
STArray.prototype.collect = function(fun, object) {
    var fun = ST.P(fun);

    var a = new STArray();
    for (var i = 0; i < this.length; i++) {
        if (fun.call(object, this[i], i)) a.push(this[i]);
    }
    return a;
};

/**
 * Returns a new array containing only items where callback returns false
 */
STArray.prototype.reject = function(fun, object) {
    var fun = ST.P(fun);

    var a = new STArray();
    for (var i = 0; i < this.length; i++) {
        if (!fun.call(object, this[i], i)) a.push(this[i]);
    }
    return a;
};

STArray.prototype.min = function(initial)
{
    var value = initial || 0;
    for (var i = 0; i < this.length; i++) {
        if (this[i] < value) value = this[i];
    }
    return value;
};

STArray.prototype.max = function(initial)
{
    var value = initial || 0;
    for (var i = 0; i < this.length; i++) {
        if (this[i] > value) value = this[i];
    }
    return value;
};
<commit_msg>Added STArray#eachAsync<commit_after>//Subclassed Array using Stack
//http://webreflection.blogspot.com/2008/05/habemus-array-unlocked-length-in-ie8.html
STArray = (function(){
    function STArray(){
        this.push.apply(this, Array.apply(null, arguments));
        this.$ = STArray;
    };
    STArray.prototype = new Array;
    STArray.prototype.length = 0;
    if(!new STArray(1).length){
        STArray.prototype = {length:0};
        for(var
            split = "join.pop.push.reverse.shift.slice.sort.splice.unshift".split("."),
            length = split.length;
            length;
        )
            STArray.prototype[split[--length]] = Array.prototype[split[length]];
    };
    var toString= Object.prototype.toString,
        slice   = Array.prototype.slice,
        concat  = Array.prototype.concat
    ;
    STArray.prototype.concat = function(){
        for(var Array = this.slice(0), i = 0, length = arguments.length; i < length; ++i){
            if(toString.call(arguments[i]) != "[object Array]")
                arguments[i] = typeof arguments[i] == "object" ? slice.call(arguments[i]) : [arguments[i]];
        };
        Array.push.apply(Array, concat.apply([], arguments));
        return  Array;
    };
    STArray.prototype.toString = STArray.prototype.join;
    STArray.prototype.constructor = STArray;
    return STArray;
})();

STArray.create = function()
{
    var a = new STArray();
    if (arguments.length) {
        a.append(arguments);
    }
    return a;
};

STArray.createWithArray = function(array)
{
    return new STArray().append(array);
};

if (!STArray.prototype.indexOf) {
    STArray.prototype.indexOf = function(v, n)
    {
        n = (n == null) ? 0 : n;
        var m = this.length;
        for (var i = n; i < m; i++) {
            if (this[i] == v) return i;
        }
        return -1;
    };
}

/**
 * Runs the specified callback function for each item in this array.
 *
 * @param {Function} fun Callback function
 */
STArray.prototype.each = function(fun, object) {
    var fun = ST.P(fun);

    for (var i = 0; i < this.length; i++) {
        if (fun.call(object, this[i], i) == 'break') break;
    }

    return this;
};

/**
 * Runs the specified callback function for each item in this array, in an
 * asynchronous manner.
 *
 * @param {Function} fun Callback function
 *
 * Options:
 *      done:       callback to call when all complete
 *      steps:      total number of synchronous steps to take
 *  or  iteration:  number of items to process in each iteration
 */
STArray.prototype.eachAsync = function(fun, options) {
    var self = this;
    var opts = options || {};
    var fun = ST.P(fun);

    var iteration = 1;
    if (opts.steps) iteration = Math.round(this.length / opts.steps);
    if (opts.iteration) iteration = opts.iteration;
    if (iteration < 1) iteration = 1;

    var i = 0;
    var loop = iteration - 1;
    var step = function() {
        fun.call(opts.object || null, self[i], i);
        i++;
        if (i < self.length) {
            if (loop > 0) {
                loop--;
                step();
            } else {
                loop = iteration - 1;
                setTimeout(step, 1);
            }
        } else if (opts.done) {
            setTimeout(opts.done, 1);
        }
    }
    setTimeout(step, 1);

    return this;
};

/**
 * Removes all items from this array.
 */
STArray.prototype.empty = function()
{
    this.length = 0;
    return this;
};

/**
 * Calls the release method on each item, then removes all items in this Array.
 */
STArray.prototype.releaseAndEmpty = function() {
    this.each('release').length = 0;
    return this;
};

/**
 * Returns true if array is empty (contains no items).
 */
STArray.prototype.isEmpty = function()
{
    return this.length == 0;
};

/**
 * Returns last item in this array, or null if empty.
 */
STArray.prototype.last = function()
{
    if (this.length == 0) return null;
    return this[this.length-1];
};

/**
 * Returns true if array contains the specified item.
 */
STArray.prototype.has = function(object)
{
    return this.indexOf(object) >= 0;
};

/**
 * Returns true if callback function for at least one array member returns
 * true.
 *
 * @param {Function} callback Callback function
 */
STArray.prototype.any = function(fun, object)
{
    var fun = ST.P(fun);

    for (var i = 0; i < this.length; i++) {
        if (fun.call(object, this[i], i)) return true;
    }
    return false;
};

/**
 * Returns true if callback function for every array member returns true.
 *
 * @param {Function} callback Callback function
 */
STArray.prototype.all = function(fun, object)
{
    var fun = ST.P(fun);

    for (var i = 0; i < this.length; i++) {
        if (!fun.call(object, this[i], i)) return false;
    }
    return true;
};

/**
 * Returns a new copy of array with callback function applied to each item.
 */
STArray.prototype.map = function(fun, object)
{
    var fun = ST.P(fun);

    var res = new STArray();
    for (var i = 0; i < this.length; i++) {
        res.push(fun.call(object, this[i], i, this));
    }
    return res;
};

/**
 * Maps all items through a callback function, and returns a standard Array
 * object.
 */
STArray.prototype.mapToStdArray = function(fun, thisp)
{
    var fun = ST.P(fun);

    var res = [];
    for (var i = 0; i < this.length; i++) {
        res.push(fun.call(thisp || null, this[i], i, this));
    }
    return res;
};

/**
 * Creates a copy of array as a standard Array object.
 */
STArray.prototype.toStdArray = function()
{
    var res = [];
    for (var i = 0; i < this.length; i++) {
        res.push(this[i]);
    }
    return res;
};

/**
 * Returns sum of all items.
 */
STArray.prototype.sum = function(initial)
{
    var c = initial || 0;
    for (var i = 0; i < this.length; i++) {
        c += this[i];
    }
    return c;
};

/**
 * Adds items in another array to the end of this one.
 */
STArray.prototype.append = function(array)
{
    this.push.apply(this, array);
    return this;
};

/**
 * Inserts an item at the specified index in Array.
 */
STArray.prototype.insert = function(index, item)
{
    this.splice(index, 0, item);
};

/**
 * Removes the given item from this array, if found,
 */
STArray.prototype.remove = function(object)
{
    for (i = 0; i < this.length; i++) {
        if (this[i] == object) {
            this.splice(i--, 1);
        }
    }
};

/**
 * Removes the item at the given index from this array.
 */
STArray.prototype.removeAtIndex = function(index)
{
    this.splice(index, 1);
};

/**
 * Returns the first item in this array where callback(item) evaluates true
 */
STArray.prototype.find = function(fun, object)
{
    var fun = ST.P(fun);

    for (var i = 0; i < this.length; i++) {
        if (fun.call(object, this[i], i)) return this[i];
    }
    return null;
};

/**
 * Removes all items from this array where callback(item) evaluates to true
 */
STArray.prototype.findRemove = function(fun, object)
{
    var fun = ST.P(fun);

    for (var i = 0; i < this.length; i++) {
        if (fun.call(object, this[i], i)) {
            this.splice(i, 1);
            i--;
        }
    }
    return null;
};

STArray.prototype.findBy = function(key, value) {
    for (var i = 0; i < this.length; i++) {
        if (this[i][key] == value) return this[i];
    }
    return null;
};

/**
 * Removes from array any items with index greater than specified index.
 */
STArray.prototype.trimTo = function(index)
{
    if (this.length > (index + 1)) {
        this.splice(index + 1, this.length - (index+1));
    }
};

/**
 * Returns a new array with the same items as this one (shallow copy).
 */
STArray.prototype.copy = function()
{
    return this.slice();
};

/**
 * Returns a new array containing items within the specified range.
 */
STArray.prototype.slice = function(from, length)
{
    var min = from || 0;
    var max = this.length - 1 - min;
    if (length) max = Math.min(max, min + length - 1);
    var a = STArray.create();
    for (var i = min; i <= max; i++) {
        a.push(this[i]);
    }
    return a;
};

/**
 * Returns a new array with no duplicates.
 */
STArray.prototype.unique = function()
{
    // Build a hash of array items, indexed by unique key
    var h = {};
    for (var i = 0; i < this.length; i++) {
        // Use _uid property as unique key if available, otherwise convert
        // object to string for key.
        h[this[i] && this[i]._uid || this[i]] = this[i];
    }

    // Build new array with now unique items in hash
    var a = new STArray();
    for (i in h) a.push(h[i]);
    return a;
};

/**
 * Returns a new array containing only items where callback returns true
 */
STArray.prototype.collect = function(fun, object) {
    var fun = ST.P(fun);

    var a = new STArray();
    for (var i = 0; i < this.length; i++) {
        if (fun.call(object, this[i], i)) a.push(this[i]);
    }
    return a;
};

/**
 * Returns a new array containing only items where callback returns false
 */
STArray.prototype.reject = function(fun, object) {
    var fun = ST.P(fun);

    var a = new STArray();
    for (var i = 0; i < this.length; i++) {
        if (!fun.call(object, this[i], i)) a.push(this[i]);
    }
    return a;
};

STArray.prototype.min = function(initial)
{
    var value = initial || 0;
    for (var i = 0; i < this.length; i++) {
        if (this[i] < value) value = this[i];
    }
    return value;
};

STArray.prototype.max = function(initial)
{
    var value = initial || 0;
    for (var i = 0; i < this.length; i++) {
        if (this[i] > value) value = this[i];
    }
    return value;
};
<|endoftext|>


<commit_before><commit_msg>removed TapTimeout class from framework.<commit_after><|endoftext|>


<commit_before><commit_msg>Found a somewhat working hack for updating the postcss source map after the parsing.<commit_after><|endoftext|>


<commit_before>import log from 'fancy-log'
import chalk from 'chalk'
import { mapUrlToPage, getViewsMock } from '../lib/utils'

export default function (options) {
  return async (ctx, next) => {
    const page = mapUrlToPage(ctx.url, options.urlMaps)
    if (page) {
      const data = getViewsMock(page, options.viewsMockPath)
      log(chalk.blue(`Render page: ${page}`))
      options.verbose && log(chalk.blue(`Render data: ${JSON.stringify(data)}`))
      await ctx.render(page, data)
    } else {
      await next()
    }
  }
}
<commit_msg>Fix render path error<commit_after>import log from 'fancy-log'
import chalk from 'chalk'
import { mapUrlToPage, getViewsMock } from '../lib/utils'

export default function (options) {
  return async (ctx, next) => {
    const page = mapUrlToPage(ctx.path, options.urlMaps)
    if (page) {
      const data = getViewsMock(page, options.viewsMockPath)
      log(chalk.blue(`Render page: ${page}`))
      options.verbose && log(chalk.blue(`Render data: ${JSON.stringify(data)}`))
      await ctx.render(page, data)
    } else {
      await next()
    }
  }
}
<|endoftext|>


<commit_before>"use strict";

const crypto = require('crypto');

const waigo = global.waigo,
  _ = waigo._,
  Q = waigo.load('support/promise'),
  errors = waigo.load('support/errors'),
  Document = waigo.load('support/models/document'),
  RethinkDbModel = waigo.load('support/models/model').RethinkDbModel,
  adminConfig = waigo.load('models/user/adminConfig'),
  tableDef = waigo.load('models/user/tableDef'),
  docMethods = waigo.load('models/user/docMethods');

const randomBytesQ = Q.promisify(crypto.pseudoRandomBytes);

class Model extends RethinkDbModel {
  constructor (app) {
    super(app, app.db, {
      name: "User",
      def: tableDef,
      adminConfig: adminConfig,
      docMethods: docMethods,
    });
  }

  /**
   * Get user by username.
   * @return {User}
   */
  * getByUsername (username) {
    let ret = yield this._qry().filter(function(user) {
      return user('username').eq(username);
    }).run();

    return this._wrap(_.get(ret, '0'));
  }

  /**
   * Get user by email address.
   * @return {User}
   */
  * getByEmail (email) {
    let ret = yield this._qry().filter(function(user) {
      return user('emails')('email').eq(email)
    }).run();

    return this._wrap(_.get(ret, '0'));
  }

  /**
   * Get user by email address or username.
   * @return {User}
   */
  * getByEmailOrUsername (str) {
    let ret = yield this._qry().filter(function(user) {
      return user('emails')('email').eq(str).or(user('username').eq(str));
    }).run();

    return this._wrap(_.get(ret, '0'));
  }

  /**
   * Find all admin users.
   * @return {Array}
   */
  * findAdminUsers () {
    let ret = yield this._qry().filter(function(user) {
      return user('roles').contains('admin')
    }).run();

    return this._wrap(ret);
  }

  /**
   * Get whether any admin users exist.
   * @return {Number}
   */
  * haveAdminUsers () {
    let count = yield this._qry().count(function(user) {
      return user('roles').contains('admin')
    }).run();

    return count > 0;
  }

  /**
   * Generate a secure SHA256 representing given password.
   * @param {String} password The password.
   * @param {String} [salt] Salt to use.
   * @return {String} hash to store
   */
  * generatePasswordHash (password, salt) {
    let hash = crypto.createHash('sha256');

    salt = salt || (yield randomBytesQ(64)).toString('hex');
    hash.update(salt);
    hash.update(password);

    return salt + '-' + hash.digest('hex');
  }

  /**
   * Register a new user
   * @param {Object} properties User props.
   * @param {String} properties.username Username.
   * @param {Object} properties.roles Roles
   * @return {User} The registered user.
   */
  * register (properties) {
    // create user
    let attrs = {
      username: properties.username,
      emails: [],
      auth: [],
      profile: _.extend({
        displayName: properties.username,
      }, properties.profile),
      roles: properties.roles,
    };

    if (properties.email) {
      attrs.emails.push(
        {
          email: properties.email,
          verified: !!properties.emailVerified,
        }
      );
    }

    if (properties.password) {
      attrs.auth.push(
        {
          type: 'password',
          token: yield this.generatePasswordHash(properties.password),
        }
      );
    }

    let user = yield this._insert(attrs);

    if (!user) {
      throw new Error('Error creating new user: ' + properties.username);
    }

    // log activity
    this.app.events.emit('record', 'register', user);

    // notify admins
    this.app.events.emit('notify', 'admins', `New user: ${user.id} - ${user.username}`);

    return user;
  }

  * loadLoggedIn (context) {
    let userId = _.get(context, 'session.user.id');

    if (!userId) {
      return null;
    }

    return yield this._get(userId);
  }

}

module.exports = Model;
<commit_msg>fix get by email query<commit_after>"use strict";

const crypto = require('crypto');

const waigo = global.waigo,
  _ = waigo._,
  Q = waigo.load('support/promise'),
  errors = waigo.load('support/errors'),
  Document = waigo.load('support/models/document'),
  RethinkDbModel = waigo.load('support/models/model').RethinkDbModel,
  adminConfig = waigo.load('models/user/adminConfig'),
  tableDef = waigo.load('models/user/tableDef'),
  docMethods = waigo.load('models/user/docMethods');

const randomBytesQ = Q.promisify(crypto.pseudoRandomBytes);

class Model extends RethinkDbModel {
  constructor (app) {
    super(app, app.db, {
      name: "User",
      def: tableDef,
      adminConfig: adminConfig,
      docMethods: docMethods,
    });
  }

  /**
   * Get user by username.
   * @return {User}
   */
  * getByUsername (username) {
    let ret = yield this._qry().filter(function(user) {
      return user('username').eq(username);
    }).run();

    return this._wrap(_.get(ret, '0'));
  }

  /**
   * Get user by email address.
   * @return {User}
   */
  * getByEmail (email) {
    const r = this.db;

    let ret = yield this._qry().filter(
      r.row('emails').contains(function(e) {
        return e('email').eq(email);
      })
    ).run();

    return this._wrap(_.get(ret, '0'));
  }

  /**
   * Get user by email address or username.
   * @return {User}
   */
  * getByEmailOrUsername (str) {
    let ret = yield this._qry().filter(function(user) {
      return user('emails')('email').eq(str).or(user('username').eq(str));
    }).run();

    return this._wrap(_.get(ret, '0'));
  }

  /**
   * Find all admin users.
   * @return {Array}
   */
  * findAdminUsers () {
    let ret = yield this._qry().filter(function(user) {
      return user('roles').contains('admin')
    }).run();

    return this._wrap(ret);
  }

  /**
   * Get whether any admin users exist.
   * @return {Number}
   */
  * haveAdminUsers () {
    let count = yield this._qry().count(function(user) {
      return user('roles').contains('admin')
    }).run();

    return count > 0;
  }

  /**
   * Generate a secure SHA256 representing given password.
   * @param {String} password The password.
   * @param {String} [salt] Salt to use.
   * @return {String} hash to store
   */
  * generatePasswordHash (password, salt) {
    let hash = crypto.createHash('sha256');

    salt = salt || (yield randomBytesQ(64)).toString('hex');
    hash.update(salt);
    hash.update(password);

    return salt + '-' + hash.digest('hex');
  }

  /**
   * Register a new user
   * @param {Object} properties User props.
   * @param {String} properties.username Username.
   * @param {Object} properties.roles Roles
   * @return {User} The registered user.
   */
  * register (properties) {
    // create user
    let attrs = {
      username: properties.username,
      emails: [],
      auth: [],
      profile: _.extend({
        displayName: properties.username,
      }, properties.profile),
      roles: properties.roles,
    };

    if (properties.email) {
      attrs.emails.push(
        {
          email: properties.email,
          verified: !!properties.emailVerified,
        }
      );
    }

    if (properties.password) {
      attrs.auth.push(
        {
          type: 'password',
          token: yield this.generatePasswordHash(properties.password),
        }
      );
    }

    let user = yield this._insert(attrs);

    if (!user) {
      throw new Error('Error creating new user: ' + properties.username);
    }

    // log activity
    this.app.events.emit('record', 'register', user);

    // notify admins
    this.app.events.emit('notify', 'admins', `New user: ${user.id} - ${user.username}`);

    return user;
  }

  * loadLoggedIn (context) {
    let userId = _.get(context, 'session.user.id');

    if (!userId) {
      return null;
    }

    return yield this._get(userId);
  }

}

module.exports = Model;
<|endoftext|>


<commit_before>( function(Dataflow) {

  var Edge = Dataflow.prototype.module("edge");

  // Thanks bobince http://stackoverflow.com/a/3642265/592125
  var makeSvgElement = function(tag, attrs) {
    var svg = document.createElementNS('http://www.w3.org/2000/svg', tag);
    for (var k in attrs) {
      if (k === "xlink:href") {
        // Pssh namespaces...
        svg.setAttributeNS('http://www.w3.org/1999/xlink','href', attrs[k]);
      } else {
        svg.setAttribute(k, attrs[k]);
      }
    }
    return svg;
  };

  Edge.View = Backbone.View.extend({
    tagName: "div",
    className: "edge",
    positions: null,
    initialize: function() {
      this.positions = {
        from: null,
        to: null
      };
      // Render on source/target view move
      if (this.model.source) {
        this.model.source.parentNode.on("change:x change:y change:w", this.render, this);
        // this.model.source.parentNode.inputs.on("add remove", this.render, this);
        // this.model.source.parentNode.outputs.on("add remove", this.render, this);
      }
      if (this.model.target) {
        this.model.target.parentNode.on("change:x change:y", this.render, this);
      }
      // Set port plug active
      if (this.model.source && this.model.source.view) {
        this.model.source.view.plugSetActive();
      }
      if (this.model.target && this.model.target.view) {
        this.model.target.view.plugSetActive();
      }
      // Made SVG elements
      this.el = makeSvgElement("g", {
        "class": "edge"
      });
      this.elEdge = makeSvgElement("path", {
        "class": "edge-wire"
      });
      this.elShadow = makeSvgElement("path", {
        "class": "edge-shadow"
      });

      this.el.appendChild(this.elShadow);
      this.el.appendChild(this.elEdge);

      // Click handler
      var self = this;
      this.el.addEventListener("click", function(event){
        self.click(event);
      });
    },
    render: function(previewPosition){
      var source = this.model.source;
      var target = this.model.target;
      var dataflowParent, graphPos;
      if (source) {
        this.positions.from = source.view.holePosition();
      }
      else {
        // Preview
        dataflowParent = this.model.parentGraph.dataflow.$el.parent().position();
        graph = this.model.parentGraph.view.$el;
        this.positions.from = {
          left: graph.scrollLeft() + previewPosition.left - 10 - dataflowParent.left,
          top:  graph.scrollTop()  + previewPosition.top  - 30 - dataflowParent.top
        };
        // No chrome
        if (!this.model.parentGraph.dataflow.controls) {
          this.positions.from.top += 40;
        }
      }
      if (target) {
        this.positions.to = target.view.holePosition();
      } else {
        // Preview
        dataflowParent = this.model.parentGraph.dataflow.$el.parent().position();
        graph = this.model.parentGraph.view.$el;
        this.positions.to = {
          left: graph.scrollLeft() + previewPosition.left + 25 - dataflowParent.left,
          top:  graph.scrollTop()  + previewPosition.top  - 30 - dataflowParent.top
        };
        // No chrome
        if (!this.model.parentGraph.dataflow.controls) {
          this.positions.to.top += 40;
        }
      }
      var pathD = this.edgePath(this.positions);
      this.elEdge.setAttribute("d", pathD);
      this.elShadow.setAttribute("d", pathD);
      // Bounding box
      if (this.model.parentGraph && this.model.parentGraph.view){
        this.model.parentGraph.view.sizeSVG();
      }
    },
    fade: function(){
      this.el.setAttribute("class", "edge fade");
    },
    unfade: function(){
      this.el.setAttribute("class", "edge");
    },
    highlight: function(){
      this.el.setAttribute("class", "edge highlight");
    },
    unhighlight: function(){
      this.el.setAttribute("class", "edge");
    },
    edgePath: function(positions){
      var x = (positions.to.left-40) - (positions.from.left+40);
      var y = positions.to.top - positions.from.top;

      var control1 = "";
      var control2 = "";

      if (Math.abs(y) > Math.abs(x)) {
        if (y > 0) {
          if (x > 0) {
            control1 = " L " + (positions.from.left+40+x/2) + " " + (positions.from.top+x/2);
            control2 = " L " + (positions.to.left-40-x/2) + " " + (positions.to.top-x/2);
          } else if (x < 0) {
            control1 = " L " + (positions.from.left+40+x/2) + " " + (positions.from.top-x/2);
            control2 = " L " + (positions.to.left-40-x/2) + " " + (positions.to.top+x/2);
          }
        } else if (y < 0) {
          if (x > 0) {
            control1 = " L " + (positions.from.left+40+x/2) + " " + (positions.from.top-x/2);
            control2 = " L " + (positions.to.left-40-x/2) + " " + (positions.to.top+x/2);
          } else if (x < 0) {
            control1 = " L " + (positions.from.left+40+x/2) + " " + (positions.from.top+x/2);
            control2 = " L " + (positions.to.left-40-x/2) + " " + (positions.to.top-x/2);
          }
        }
      } else if (Math.abs(y) < Math.abs(x)) {
        if (x > 0) {
          if (y > 0) {
            control1 = " L " + (positions.from.left+40+y/2) + " " + (positions.from.top+y/2);
            control2 = " L " + (positions.to.left-40-y/2) + " " + (positions.to.top-y/2);
          } else if (y < 0) {
            control1 = " L " + (positions.from.left+40-y/2) + " " + (positions.from.top+y/2);
            control2 = " L " + (positions.to.left-40+y/2) + " " + (positions.to.top-y/2);
          }
        } else if (x < 0) {
          if (y > 0) {
            control1 = " L " + (positions.from.left+40-y/2) + " " + (positions.from.top+y/2);
            control2 = " L " + (positions.to.left-40+y/2) + " " + (positions.to.top-y/2);
          } else if (y < 0) {
            control1 = " L " + (positions.from.left+40+y/2) + " " + (positions.from.top+y/2);
            control2 = " L " + (positions.to.left-40-y/2) + " " + (positions.to.top-y/2);
          }
        }
      }

      return "M " + positions.from.left + " " + positions.from.top +
        " L " + (positions.from.left+40) + " " + positions.from.top +
        control1 + control2 +
        " L " + (positions.to.left-40) + " " + positions.to.top +
        " L " + positions.to.left + " " + positions.to.top;
    },
    remove: function(){
      var source = this.model.source;
      var target = this.model.target;
      // Remove listeners
      if (source) {
        source.parentNode.off(null, null, this);
      }
      if (target) {
        target.parentNode.off(null, null, this);
      }
      // Check if port plug is still active
      if (source) {
        source.view.plugCheckActive();
      }
      if (target) {
        target.view.plugCheckActive();
      }
      // Remove element
      this.el.parentNode.removeChild(this.el);
    },
    click: function(event){
      // Highlight
      this.highlight();
      this.bringToTop();
    },
    bringToTop: function(){
      this.model.bringToTop();
      var parent = this.el.parentNode;
      if(parent){
        parent.removeChild(this.el);
        parent.appendChild(this.el);
      }
    }
  });

}(Dataflow) );
<commit_msg>whole-number svg paths<commit_after>( function(Dataflow) {

  var Edge = Dataflow.prototype.module("edge");

  // Thanks bobince http://stackoverflow.com/a/3642265/592125
  var makeSvgElement = function(tag, attrs) {
    var svg = document.createElementNS('http://www.w3.org/2000/svg', tag);
    for (var k in attrs) {
      if (k === "xlink:href") {
        // Pssh namespaces...
        svg.setAttributeNS('http://www.w3.org/1999/xlink','href', attrs[k]);
      } else {
        svg.setAttribute(k, attrs[k]);
      }
    }
    return svg;
  };

  Edge.View = Backbone.View.extend({
    tagName: "div",
    className: "edge",
    positions: null,
    initialize: function() {
      this.positions = {
        from: null,
        to: null
      };
      // Render on source/target view move
      if (this.model.source) {
        this.model.source.parentNode.on("change:x change:y change:w", this.render, this);
        // this.model.source.parentNode.inputs.on("add remove", this.render, this);
        // this.model.source.parentNode.outputs.on("add remove", this.render, this);
      }
      if (this.model.target) {
        this.model.target.parentNode.on("change:x change:y", this.render, this);
      }
      // Set port plug active
      if (this.model.source && this.model.source.view) {
        this.model.source.view.plugSetActive();
      }
      if (this.model.target && this.model.target.view) {
        this.model.target.view.plugSetActive();
      }
      // Made SVG elements
      this.el = makeSvgElement("g", {
        "class": "edge"
      });
      this.elEdge = makeSvgElement("path", {
        "class": "edge-wire"
      });
      this.elShadow = makeSvgElement("path", {
        "class": "edge-shadow"
      });

      this.el.appendChild(this.elShadow);
      this.el.appendChild(this.elEdge);

      // Click handler
      var self = this;
      this.el.addEventListener("click", function(event){
        self.click(event);
      });
    },
    render: function(previewPosition){
      var source = this.model.source;
      var target = this.model.target;
      var dataflowParent, graphPos;
      if (source) {
        this.positions.from = source.view.holePosition();
      }
      else {
        // Preview
        dataflowParent = this.model.parentGraph.dataflow.$el.parent().position();
        graph = this.model.parentGraph.view.$el;
        this.positions.from = {
          left: graph.scrollLeft() + previewPosition.left - 10 - dataflowParent.left,
          top:  graph.scrollTop()  + previewPosition.top  - 30 - dataflowParent.top
        };
        // No chrome
        if (!this.model.parentGraph.dataflow.controls) {
          this.positions.from.top += 40;
        }
      }
      if (target) {
        this.positions.to = target.view.holePosition();
      } else {
        // Preview
        dataflowParent = this.model.parentGraph.dataflow.$el.parent().position();
        graph = this.model.parentGraph.view.$el;
        this.positions.to = {
          left: graph.scrollLeft() + previewPosition.left + 25 - dataflowParent.left,
          top:  graph.scrollTop()  + previewPosition.top  - 30 - dataflowParent.top
        };
        // No chrome
        if (!this.model.parentGraph.dataflow.controls) {
          this.positions.to.top += 40;
        }
      }
      this.positions.from.left = Math.floor(this.positions.from.left);
      this.positions.from.top = Math.floor(this.positions.from.top);
      this.positions.to.left = Math.floor(this.positions.to.left);
      this.positions.to.top = Math.floor(this.positions.to.top);
      var pathD = this.edgePath(this.positions);
      this.elEdge.setAttribute("d", pathD);
      this.elShadow.setAttribute("d", pathD);
      // Bounding box
      if (this.model.parentGraph && this.model.parentGraph.view){
        this.model.parentGraph.view.sizeSVG();
      }
    },
    fade: function(){
      this.el.setAttribute("class", "edge fade");
    },
    unfade: function(){
      this.el.setAttribute("class", "edge");
    },
    highlight: function(){
      this.el.setAttribute("class", "edge highlight");
    },
    unhighlight: function(){
      this.el.setAttribute("class", "edge");
    },
    edgePath: function(positions){
      var x = (positions.to.left-40) - (positions.from.left+40);
      var halfX = Math.floor(x/2);
      var halfX2 = x-halfX;
      var y = positions.to.top - positions.from.top;
      var halfY = Math.floor(y/2);
      var halfY2 = y-halfY;

      // Todo: check if this wire path is occupied, if so shift it over

      var control1 = "";
      var control2 = "";

      if (Math.abs(y) > Math.abs(x)) {
        // More vertical travel
        if (y > 0) {
          if (x > 0) {
            control1 = " L " + (positions.from.left+40+halfX) + " " + (positions.from.top+halfX);
            control2 = " L " + (positions.to.left-40-halfX2) + " " + (positions.to.top-halfX2);
          } else if (x < 0) {
            control1 = " L " + (positions.from.left+40+halfX) + " " + (positions.from.top-halfX);
            control2 = " L " + (positions.to.left-40-halfX2) + " " + (positions.to.top+halfX2);
          }
        } else if (y < 0) {
          if (x > 0) {
            control1 = " L " + (positions.from.left+40+halfX) + " " + (positions.from.top-halfX);
            control2 = " L " + (positions.to.left-40-halfX2) + " " + (positions.to.top+halfX2);
          } else if (x < 0) {
            control1 = " L " + (positions.from.left+40+halfX) + " " + (positions.from.top+halfX);
            control2 = " L " + (positions.to.left-40-halfX2) + " " + (positions.to.top-halfX2);
          }
        }
      } else if (Math.abs(y) < Math.abs(x)) {
        // More horizontal travel
        if (x > 0) {
          if (y > 0) {
            control1 = " L " + (positions.from.left+40+halfY) + " " + (positions.from.top+halfY);
            control2 = " L " + (positions.to.left-40-halfY2) + " " + (positions.to.top-halfY2);
          } else if (y < 0) {
            control1 = " L " + (positions.from.left+40-halfY) + " " + (positions.from.top+halfY);
            control2 = " L " + (positions.to.left-40+halfY2) + " " + (positions.to.top-halfY2);
          }
        } else if (x < 0) {
          if (y > 0) {
            control1 = " L " + (positions.from.left+40-halfY) + " " + (positions.from.top+halfY);
            control2 = " L " + (positions.to.left-40+halfY2) + " " + (positions.to.top-halfY2);
          } else if (y < 0) {
            control1 = " L " + (positions.from.left+40+halfY) + " " + (positions.from.top+halfY);
            control2 = " L " + (positions.to.left-40-halfY2) + " " + (positions.to.top-halfY2);
          }
        }
      }

      return "M " + positions.from.left + " " + positions.from.top +
        " L " + (positions.from.left+40) + " " + positions.from.top +
        control1 + control2 +
        " L " + (positions.to.left-40) + " " + positions.to.top +
        " L " + positions.to.left + " " + positions.to.top;
    },
    remove: function(){
      var source = this.model.source;
      var target = this.model.target;
      // Remove listeners
      if (source) {
        source.parentNode.off(null, null, this);
      }
      if (target) {
        target.parentNode.off(null, null, this);
      }
      // Check if port plug is still active
      if (source) {
        source.view.plugCheckActive();
      }
      if (target) {
        target.view.plugCheckActive();
      }
      // Remove element
      this.el.parentNode.removeChild(this.el);
    },
    click: function(event){
      // Highlight
      this.highlight();
      this.bringToTop();
    },
    bringToTop: function(){
      this.model.bringToTop();
      var parent = this.el.parentNode;
      if(parent){
        parent.removeChild(this.el);
        parent.appendChild(this.el);
      }
    }
  });

}(Dataflow) );
<|endoftext|>


<commit_before>/**
 * Copyright 2015 CANAL+ Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var _ = require("canal-js-utils/misc");
var assert = require("canal-js-utils/assert");
var bytes = require("canal-js-utils/bytes");

var DEFAULT_MIME_TYPES = {
  audio: "audio/mp4",
  video: "video/mp4",
  text: "application/ttml+xml",
};

var DEFAULT_CODECS = {
  audio: "mp4a.40.2",
  video: "avc1.4D401E",
};

var MIME_TYPES = {
  "AACL": "audio/mp4",
  "AVC1": "video/mp4",
  "H264": "video/mp4",
  "TTML": "application/ttml+xml+mp4"
};

var CODECS = {
  "AACL": "mp4a.40.5",
  "AACH": "mp4a.40.5",
  "AVC1": "avc1.4D401E",
  "H264": "avc1.4D401E",
};

var profiles = {
  audio: [
    ["Bitrate",          "bitrate",          parseInt],
    ["AudioTag",         "audiotag",         parseInt],
    ["FourCC",           "mimeType",         MIME_TYPES],
    ["FourCC",           "codecs",           CODECS],
    ["Channels",         "channels",         parseInt],
    ["SamplingRate",     "samplingRate",     parseInt],
    ["BitsPerSample",    "bitsPerSample",    parseInt],
    ["PacketSize",       "packetSize",       parseInt],
    ["CodecPrivateData", "codecPrivateData", String],
  ],
  video: [
    ["Bitrate",          "bitrate",          parseInt],
    ["FourCC",           "mimeType",         MIME_TYPES],
    ["FourCC",           "codecs",           CODECS],
    ["MaxWidth",         "width",            parseInt],
    ["MaxHeight",        "height",           parseInt],
    ["CodecPrivateData", "codecPrivateData", String],
  ],
  text: [
    ["Bitrate", "bitrate",  parseInt],
    ["FourCC",  "mimeType", MIME_TYPES],
  ]
};

function parseBoolean(val) {
  if (typeof val == "boolean") {
    return val;
  }
  else if (typeof val == "string") {
    return val.toUpperCase() === "TRUE";
  }
  else {
    return true;
  }
}

function calcLastRef(index) {
  var { ts, r, d } = _.last(index.timeline);
  return ((ts + (r+1)*d) / index.timescale);
}

function getKeySystems(keyIdBytes) {
  return [
    {
      // Widevine
      systemId: "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",
      privateData: bytes.concat([0x08, 0x01, 0x12, 0x10], keyIdBytes),
      // keyIds: [keyIdBytes],
    },
    // {
    //   // Clearkey
    //   // (https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html)
    //   systemId: "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b",
    //   privateData: bytes.strToBytes(JSON.stringify({
    //     kids: [bytes.toBase64URL(bytes.bytesToStr(keyIdBytes))],
    //     type: "temporary"
    //   }))
    // }
  ];
}

function createSmoothStreamingParser(parserOptions={}) {

  var SUGGESTED_PERSENTATION_DELAY = parserOptions.suggestedPresentationDelay || 20;

  // Reference time to map the stream-clock to the wall-clock is based
  // on the date 06/01/2013 for C+ SmoothStreaming streams, instead of
  // 01/01/1970
  var REFERENCE_DATE_TIME = parserOptions.referenceDateTime || Date.UTC(1970, 0, 1, 0, 0, 0, 0) / 1000;
  var MIN_REPRESENTATION_BITRATE = parserOptions.minRepresentationBitrate || 190000;

  var keySystems = parserOptions.keySystems || getKeySystems;

  function getHexKeyId(buf) {
    var len = bytes.le2toi(buf, 8);
    var xml = bytes.bytesToUTF16Str(buf.subarray(10, 10 + len));
    var doc = new DOMParser().parseFromString(xml, "application/xml");
    var kid = doc.querySelector("KID").textContent;
    return bytes.guidToUuid(atob(kid)).toLowerCase();
  }

  function reduceChildren(root, fn, init) {
    var node = root.firstElementChild, r = init;
    while (node) {
      r = fn(r, node.nodeName, node);
      node = node.nextElementSibling;
    }
    return r;
  }

  function parseProtection(root) {
    var header = root.firstElementChild;
    assert.equal(header.nodeName, "ProtectionHeader", "parser: Protection should have ProtectionHeader child");
    var privateData = bytes.strToBytes(atob(header.textContent));
    var keyId = getHexKeyId(privateData);
    var keyIdBytes = bytes.hexToBytes(keyId);

    // remove possible braces
    var systemId = header.getAttribute("SystemID").toLowerCase()
      .replace(/\{|\}/g, "");

    return {
      keyId: keyId,
      keySystems: [
        {
          systemId,
          privateData,
          // keyIds: [keyIdBytes],
        }
      ].concat(keySystems(keyIdBytes))
    };
  }

  function parseC(node, timeline) {
    var l = timeline.length;
    var prev = l > 0 ? timeline[l - 1] : { d: 0, ts: 0, r: 0 };
    var d = +node.getAttribute("d");
    var t =  node.getAttribute("t");
    var r = +node.getAttribute("r");

    // in smooth streaming format,
    // r refers to number of same duration
    // chunks, not repetitions (defers from DASH)
    if (r)  r--;

    if (l > 0 && d == prev.d && t == null) {
      prev.r += (r || 0) + 1;
    }
    else {
      var ts = (t == null)
        ? prev.ts + prev.d * (prev.r + 1)
        : +t;
      timeline.push({ d, ts, r });
    }
    return timeline;
  }

  function parseQualityLevel(q, prof) {
    return _.reduce(prof, (obj, [key, name, parse]) => {
      obj[name] = _.isFunction(parse)
        ? parse(q.getAttribute(key))
        : parse[q.getAttribute(key)];
      return obj;
    }, {});
  }

  // Parse the adaptations (<StreamIndex>) tree containing
  // representations (<QualityLevels>) and timestamp indexes (<c>).
  // Indexes can be quite huge, and this function needs to
  // to be optimized.
  function parseAdaptation(root, timescale) {
    if (root.hasAttribute("Timescale")) {
      timescale = +root.getAttribute("Timescale");
    }

    var type = root.getAttribute("Type");
    var subType = root.getAttribute("Subtype");
    var profile = profiles[type];

    assert(profile, "parser: unrecognized QualityLevel type " + type);

    var representationCount = 0;

    var { representations, index } = reduceChildren(root, (res, name, node) => {
      switch (name) {
      case "QualityLevel":
        var rep = parseQualityLevel(node, profile);

        // filter out video representations with small bitrates
        if (type != "video" || rep.bitrate > MIN_REPRESENTATION_BITRATE) {
          rep.id = representationCount++;
          res.representations.push(rep);
        }

        break;
      case "c":
        res.index.timeline = parseC(node, res.index.timeline);
        break;
      }
      return res;
    }, {
      representations: [],
      index: {
        timeline: [],
        indexType: "timeline",
        timescale: timescale,
        initialization: {},
      },
    });

    // we assume that all representations have the same
    // codec and mimeType
    assert(representations.length, "parser: adaptation should have at least one representation");

    // apply default codec if non-supported
    var codecs = representations[0].codecs;
    if (!codecs) {
      codecs = DEFAULT_CODECS[type];
      _.each(representations, rep => rep.codecs = codecs);
    }

    // apply default mimetype if non-supported
    var mimeType = representations[0].mimeType;
    if (!mimeType) {
      mimeType = DEFAULT_MIME_TYPES[type];
      _.each(representations, rep => rep.mimeType = mimeType);
    }

    // TODO(pierre): real ad-insert support
    if (subType == "ADVT")
      return null;

    return {
      type,
      index,
      representations,
      name: root.getAttribute("Name"),
      lang: root.getAttribute("Language"),
      baseURL: root.getAttribute("Url"),
    };
  }

  function parseFromString(manifest) {
    return parseFromDocument(new DOMParser().parseFromString(manifest, "application/xml"));
  }

  function parseFromDocument(doc) {
    var root = doc.documentElement;
    assert.equal(root.nodeName, "SmoothStreamingMedia", "parser: document root should be SmoothStreamingMedia");
    assert(/^[2]-[0-2]$/.test(root.getAttribute("MajorVersion") + "-" + root.getAttribute("MinorVersion")),
      "Version should be 2.0, 2.1 or 2.2");

    var timescale = +root.getAttribute("Timescale") || 10000000;
    var adaptationCount = 0;

    var { protection, adaptations } = reduceChildren(root, (res, name, node) => {
      switch (name) {
      case "Protection":  res.protection = parseProtection(node);  break;
      case "StreamIndex":
        var ada = parseAdaptation(node, timescale);
        if (ada) {
          ada.id = adaptationCount++;
          res.adaptations.push(ada);
        }
        break;
      }
      return res;
    }, {
      protection:  null,
      adaptations: [],
    });

    _.each(adaptations, a => a.smoothProtection = protection);

    var
      suggestedPresentationDelay,
      presentationLiveGap,
      timeShiftBufferDepth,
      availabilityStartTime;

    var isLive = parseBoolean(root.getAttribute("IsLive"));
    if (isLive) {
      suggestedPresentationDelay = SUGGESTED_PERSENTATION_DELAY;
      timeShiftBufferDepth = +root.getAttribute("DVRWindowLength") / timescale;
      availabilityStartTime = REFERENCE_DATE_TIME;
      var video = _.find(adaptations, a => a.type == "video");
      var audio = _.find(adaptations, a => a.type == "audio");
      var lastRef = Math.min(calcLastRef(video.index), calcLastRef(audio.index));
      presentationLiveGap = Date.now() / 1000 - (lastRef + availabilityStartTime);
    }

    return {
      transportType: "smoothstreaming",
      profiles: "",
      type: isLive ? "dynamic" : "static",
      suggestedPresentationDelay,
      timeShiftBufferDepth,
      presentationLiveGap,
      availabilityStartTime,
      periods: [{
        duration:    (+root.getAttribute("Duration") || Infinity) / timescale,
        adaptations,
        laFragCount: +root.getAttribute("LookAheadFragmentCount"),
      }]
    };
  }

  function parser(val) {
    if (_.isString(val))                return parseFromString(val);
    if (val instanceof window.Document) return parseFromDocument(val);
    throw new Error("parser: unsupported type to parse");
  }

  parser.parseFromString   = parseFromString;
  parser.parseFromDocument = parseFromDocument;

  return parser;
}

module.exports = createSmoothStreamingParser;
<commit_msg>smooth: fix parseBoolean causing isLive to be always true<commit_after>/**
 * Copyright 2015 CANAL+ Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var _ = require("canal-js-utils/misc");
var assert = require("canal-js-utils/assert");
var bytes = require("canal-js-utils/bytes");

var DEFAULT_MIME_TYPES = {
  audio: "audio/mp4",
  video: "video/mp4",
  text: "application/ttml+xml",
};

var DEFAULT_CODECS = {
  audio: "mp4a.40.2",
  video: "avc1.4D401E",
};

var MIME_TYPES = {
  "AACL": "audio/mp4",
  "AVC1": "video/mp4",
  "H264": "video/mp4",
  "TTML": "application/ttml+xml+mp4"
};

var CODECS = {
  "AACL": "mp4a.40.5",
  "AACH": "mp4a.40.5",
  "AVC1": "avc1.4D401E",
  "H264": "avc1.4D401E",
};

var profiles = {
  audio: [
    ["Bitrate",          "bitrate",          parseInt],
    ["AudioTag",         "audiotag",         parseInt],
    ["FourCC",           "mimeType",         MIME_TYPES],
    ["FourCC",           "codecs",           CODECS],
    ["Channels",         "channels",         parseInt],
    ["SamplingRate",     "samplingRate",     parseInt],
    ["BitsPerSample",    "bitsPerSample",    parseInt],
    ["PacketSize",       "packetSize",       parseInt],
    ["CodecPrivateData", "codecPrivateData", String],
  ],
  video: [
    ["Bitrate",          "bitrate",          parseInt],
    ["FourCC",           "mimeType",         MIME_TYPES],
    ["FourCC",           "codecs",           CODECS],
    ["MaxWidth",         "width",            parseInt],
    ["MaxHeight",        "height",           parseInt],
    ["CodecPrivateData", "codecPrivateData", String],
  ],
  text: [
    ["Bitrate", "bitrate",  parseInt],
    ["FourCC",  "mimeType", MIME_TYPES],
  ]
};

function parseBoolean(val) {
  if (typeof val == "boolean") {
    return val;
  }
  else if (typeof val == "string") {
    return val.toUpperCase() === "TRUE";
  }
  else {
    return false;
  }
}

function calcLastRef(index) {
  var { ts, r, d } = _.last(index.timeline);
  return ((ts + (r+1)*d) / index.timescale);
}

function getKeySystems(keyIdBytes) {
  return [
    {
      // Widevine
      systemId: "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed",
      privateData: bytes.concat([0x08, 0x01, 0x12, 0x10], keyIdBytes),
      // keyIds: [keyIdBytes],
    },
    // {
    //   // Clearkey
    //   // (https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html)
    //   systemId: "1077efec-c0b2-4d02-ace3-3c1e52e2fb4b",
    //   privateData: bytes.strToBytes(JSON.stringify({
    //     kids: [bytes.toBase64URL(bytes.bytesToStr(keyIdBytes))],
    //     type: "temporary"
    //   }))
    // }
  ];
}

function createSmoothStreamingParser(parserOptions={}) {

  var SUGGESTED_PERSENTATION_DELAY = parserOptions.suggestedPresentationDelay || 20;

  // Reference time to map the stream-clock to the wall-clock is based
  // on the date 06/01/2013 for C+ SmoothStreaming streams, instead of
  // 01/01/1970
  var REFERENCE_DATE_TIME = parserOptions.referenceDateTime || Date.UTC(1970, 0, 1, 0, 0, 0, 0) / 1000;
  var MIN_REPRESENTATION_BITRATE = parserOptions.minRepresentationBitrate || 190000;

  var keySystems = parserOptions.keySystems || getKeySystems;

  function getHexKeyId(buf) {
    var len = bytes.le2toi(buf, 8);
    var xml = bytes.bytesToUTF16Str(buf.subarray(10, 10 + len));
    var doc = new DOMParser().parseFromString(xml, "application/xml");
    var kid = doc.querySelector("KID").textContent;
    return bytes.guidToUuid(atob(kid)).toLowerCase();
  }

  function reduceChildren(root, fn, init) {
    var node = root.firstElementChild, r = init;
    while (node) {
      r = fn(r, node.nodeName, node);
      node = node.nextElementSibling;
    }
    return r;
  }

  function parseProtection(root) {
    var header = root.firstElementChild;
    assert.equal(header.nodeName, "ProtectionHeader", "parser: Protection should have ProtectionHeader child");
    var privateData = bytes.strToBytes(atob(header.textContent));
    var keyId = getHexKeyId(privateData);
    var keyIdBytes = bytes.hexToBytes(keyId);

    // remove possible braces
    var systemId = header.getAttribute("SystemID").toLowerCase()
      .replace(/\{|\}/g, "");

    return {
      keyId: keyId,
      keySystems: [
        {
          systemId,
          privateData,
          // keyIds: [keyIdBytes],
        }
      ].concat(keySystems(keyIdBytes))
    };
  }

  function parseC(node, timeline) {
    var l = timeline.length;
    var prev = l > 0 ? timeline[l - 1] : { d: 0, ts: 0, r: 0 };
    var d = +node.getAttribute("d");
    var t =  node.getAttribute("t");
    var r = +node.getAttribute("r");

    // in smooth streaming format,
    // r refers to number of same duration
    // chunks, not repetitions (defers from DASH)
    if (r)  r--;

    if (l > 0 && d == prev.d && t == null) {
      prev.r += (r || 0) + 1;
    }
    else {
      var ts = (t == null)
        ? prev.ts + prev.d * (prev.r + 1)
        : +t;
      timeline.push({ d, ts, r });
    }
    return timeline;
  }

  function parseQualityLevel(q, prof) {
    return _.reduce(prof, (obj, [key, name, parse]) => {
      obj[name] = _.isFunction(parse)
        ? parse(q.getAttribute(key))
        : parse[q.getAttribute(key)];
      return obj;
    }, {});
  }

  // Parse the adaptations (<StreamIndex>) tree containing
  // representations (<QualityLevels>) and timestamp indexes (<c>).
  // Indexes can be quite huge, and this function needs to
  // to be optimized.
  function parseAdaptation(root, timescale) {
    if (root.hasAttribute("Timescale")) {
      timescale = +root.getAttribute("Timescale");
    }

    var type = root.getAttribute("Type");
    var subType = root.getAttribute("Subtype");
    var profile = profiles[type];

    assert(profile, "parser: unrecognized QualityLevel type " + type);

    var representationCount = 0;

    var { representations, index } = reduceChildren(root, (res, name, node) => {
      switch (name) {
      case "QualityLevel":
        var rep = parseQualityLevel(node, profile);

        // filter out video representations with small bitrates
        if (type != "video" || rep.bitrate > MIN_REPRESENTATION_BITRATE) {
          rep.id = representationCount++;
          res.representations.push(rep);
        }

        break;
      case "c":
        res.index.timeline = parseC(node, res.index.timeline);
        break;
      }
      return res;
    }, {
      representations: [],
      index: {
        timeline: [],
        indexType: "timeline",
        timescale: timescale,
        initialization: {},
      },
    });

    // we assume that all representations have the same
    // codec and mimeType
    assert(representations.length, "parser: adaptation should have at least one representation");

    // apply default codec if non-supported
    var codecs = representations[0].codecs;
    if (!codecs) {
      codecs = DEFAULT_CODECS[type];
      _.each(representations, rep => rep.codecs = codecs);
    }

    // apply default mimetype if non-supported
    var mimeType = representations[0].mimeType;
    if (!mimeType) {
      mimeType = DEFAULT_MIME_TYPES[type];
      _.each(representations, rep => rep.mimeType = mimeType);
    }

    // TODO(pierre): real ad-insert support
    if (subType == "ADVT")
      return null;

    return {
      type,
      index,
      representations,
      name: root.getAttribute("Name"),
      lang: root.getAttribute("Language"),
      baseURL: root.getAttribute("Url"),
    };
  }

  function parseFromString(manifest) {
    return parseFromDocument(new DOMParser().parseFromString(manifest, "application/xml"));
  }

  function parseFromDocument(doc) {
    var root = doc.documentElement;
    assert.equal(root.nodeName, "SmoothStreamingMedia", "parser: document root should be SmoothStreamingMedia");
    assert(/^[2]-[0-2]$/.test(root.getAttribute("MajorVersion") + "-" + root.getAttribute("MinorVersion")),
      "Version should be 2.0, 2.1 or 2.2");

    var timescale = +root.getAttribute("Timescale") || 10000000;
    var adaptationCount = 0;

    var { protection, adaptations } = reduceChildren(root, (res, name, node) => {
      switch (name) {
      case "Protection":  res.protection = parseProtection(node);  break;
      case "StreamIndex":
        var ada = parseAdaptation(node, timescale);
        if (ada) {
          ada.id = adaptationCount++;
          res.adaptations.push(ada);
        }
        break;
      }
      return res;
    }, {
      protection:  null,
      adaptations: [],
    });

    _.each(adaptations, a => a.smoothProtection = protection);

    var
      suggestedPresentationDelay,
      presentationLiveGap,
      timeShiftBufferDepth,
      availabilityStartTime;

    var isLive = parseBoolean(root.getAttribute("IsLive"));
    if (isLive) {
      suggestedPresentationDelay = SUGGESTED_PERSENTATION_DELAY;
      timeShiftBufferDepth = +root.getAttribute("DVRWindowLength") / timescale;
      availabilityStartTime = REFERENCE_DATE_TIME;
      var video = _.find(adaptations, a => a.type == "video");
      var audio = _.find(adaptations, a => a.type == "audio");
      var lastRef = Math.min(calcLastRef(video.index), calcLastRef(audio.index));
      presentationLiveGap = Date.now() / 1000 - (lastRef + availabilityStartTime);
    }

    return {
      transportType: "smoothstreaming",
      profiles: "",
      type: isLive ? "dynamic" : "static",
      suggestedPresentationDelay,
      timeShiftBufferDepth,
      presentationLiveGap,
      availabilityStartTime,
      periods: [{
        duration:    (+root.getAttribute("Duration") || Infinity) / timescale,
        adaptations,
        laFragCount: +root.getAttribute("LookAheadFragmentCount"),
      }]
    };
  }

  function parser(val) {
    if (_.isString(val))                return parseFromString(val);
    if (val instanceof window.Document) return parseFromDocument(val);
    throw new Error("parser: unsupported type to parse");
  }

  parser.parseFromString   = parseFromString;
  parser.parseFromDocument = parseFromDocument;

  return parser;
}

module.exports = createSmoothStreamingParser;
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc overview
 * @name angular.module.ngCookies
 */

angular.module('ngCookies', ['ng']).
  /**
   * @ngdoc object
   * @name angular.module.ng.$cookies
   * @requires $browser
   *
   * @description
   * Provides read/write access to browser's cookies.
   *
   * Only a simple Object is exposed and by adding or removing properties to/from
   * this object, new cookies are created/deleted at the end of current $eval.
   *
   * @example
   */
   factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
      var cookies = {},
          lastCookies = {},
          lastBrowserCookies,
          runEval = false,
          copy = angular.copy,
          isUndefined = angular.isUndefined;

      //creates a poller fn that copies all cookies from the $browser to service & inits the service
      $browser.addPollFn(function() {
        var currentCookies = $browser.cookies();
        if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
          lastBrowserCookies = currentCookies;
          copy(currentCookies, lastCookies);
          copy(currentCookies, cookies);
          if (runEval) $rootScope.$apply();
        }
      })();

      runEval = true;

      //at the end of each eval, push cookies
      //TODO: this should happen before the "delayed" watches fire, because if some cookies are not
      //      strings or browser refuses to store some cookies, we update the model in the push fn.
      $rootScope.$watch(push);

      return cookies;

      /**
       * Pushes all the cookies from the service to the browser and verifies if all cookies were stored.
       */
      function push() {
        var name,
            value,
            browserCookies,
            updated;

        //delete any cookies deleted in $cookies
        for (name in lastCookies) {
          if (isUndefined(cookies[name])) {
            $browser.cookies(name, undefined);
          }
        }

        //update all cookies updated in $cookies
        for(name in cookies) {
          value = cookies[name];
          if (!angular.isString(value)) {
            if (angular.isDefined(lastCookies[name])) {
              cookies[name] = lastCookies[name];
            } else {
              delete cookies[name];
            }
          } else if (value !== lastCookies[name]) {
            $browser.cookies(name, value);
            updated = true;
          }
        }

        //verify what was actually stored
        if (updated){
          updated = false;
          browserCookies = $browser.cookies();

          for (name in cookies) {
            if (cookies[name] !== browserCookies[name]) {
              //delete or reset all cookies that the browser dropped from $cookies
              if (isUndefined(browserCookies[name])) {
                delete cookies[name];
              } else {
                cookies[name] = browserCookies[name];
              }
              updated = true;
            }
          }
        }
      }
    }]).

  /**
   * @ngdoc object
   * @name angular.module.ng.$cookieStore
   * @requires $cookies
   *
   * @description
   * Provides a key-value (string-object) storage, that is backed by session cookies.
   * Objects put or retrieved from this storage are automatically serialized or
   * deserialized by angular's toJson/fromJson.
   * @example
   */
   factory('$cookieStore', ['$cookies', function($cookies) {

      return {
        /**
         * @ngdoc method
         * @name angular.module.ng.$cookieStore#get
         * @methodOf angular.module.ng.$cookieStore
         *
         * @description
         * Returns the value of given cookie key
         *
         * @param {string} key Id to use for lookup.
         * @returns {Object} Deserialized cookie value.
         */
        get: function(key) {
          return angular.fromJson($cookies[key]);
        },

        /**
         * @ngdoc method
         * @name angular.module.ng.$cookieStore#put
         * @methodOf angular.module.ng.$cookieStore
         *
         * @description
         * Sets a value for given cookie key
         *
         * @param {string} key Id for the `value`.
         * @param {Object} value Value to be stored.
         */
        put: function(key, value) {
          $cookies[key] = angular.toJson(value);
        },

        /**
         * @ngdoc method
         * @name angular.module.ng.$cookieStore#remove
         * @methodOf angular.module.ng.$cookieStore
         *
         * @description
         * Remove given cookie
         *
         * @param {string} key Id of the key-value pair to delete.
         */
        remove: function(key) {
          delete $cookies[key];
        }
      };

    }]);
<commit_msg>fix(docs): move $cookies and $cookieStore docs to module<commit_after>'use strict';

/**
 * @ngdoc overview
 * @name angular.module.ngCookies
 */

angular.module('ngCookies', ['ng']).
  /**
   * @ngdoc object
   * @name angular.module.ngCookies.$cookies
   * @requires $browser
   *
   * @description
   * Provides read/write access to browser's cookies.
   *
   * Only a simple Object is exposed and by adding or removing properties to/from
   * this object, new cookies are created/deleted at the end of current $eval.
   *
   * @example
   */
   factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
      var cookies = {},
          lastCookies = {},
          lastBrowserCookies,
          runEval = false,
          copy = angular.copy,
          isUndefined = angular.isUndefined;

      //creates a poller fn that copies all cookies from the $browser to service & inits the service
      $browser.addPollFn(function() {
        var currentCookies = $browser.cookies();
        if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
          lastBrowserCookies = currentCookies;
          copy(currentCookies, lastCookies);
          copy(currentCookies, cookies);
          if (runEval) $rootScope.$apply();
        }
      })();

      runEval = true;

      //at the end of each eval, push cookies
      //TODO: this should happen before the "delayed" watches fire, because if some cookies are not
      //      strings or browser refuses to store some cookies, we update the model in the push fn.
      $rootScope.$watch(push);

      return cookies;

      /**
       * Pushes all the cookies from the service to the browser and verifies if all cookies were stored.
       */
      function push() {
        var name,
            value,
            browserCookies,
            updated;

        //delete any cookies deleted in $cookies
        for (name in lastCookies) {
          if (isUndefined(cookies[name])) {
            $browser.cookies(name, undefined);
          }
        }

        //update all cookies updated in $cookies
        for(name in cookies) {
          value = cookies[name];
          if (!angular.isString(value)) {
            if (angular.isDefined(lastCookies[name])) {
              cookies[name] = lastCookies[name];
            } else {
              delete cookies[name];
            }
          } else if (value !== lastCookies[name]) {
            $browser.cookies(name, value);
            updated = true;
          }
        }

        //verify what was actually stored
        if (updated){
          updated = false;
          browserCookies = $browser.cookies();

          for (name in cookies) {
            if (cookies[name] !== browserCookies[name]) {
              //delete or reset all cookies that the browser dropped from $cookies
              if (isUndefined(browserCookies[name])) {
                delete cookies[name];
              } else {
                cookies[name] = browserCookies[name];
              }
              updated = true;
            }
          }
        }
      }
    }]).

  /**
   * @ngdoc object
   * @name angular.module.ngCookies.$cookieStore
   * @requires $cookies
   *
   * @description
   * Provides a key-value (string-object) storage, that is backed by session cookies.
   * Objects put or retrieved from this storage are automatically serialized or
   * deserialized by angular's toJson/fromJson.
   * @example
   */
   factory('$cookieStore', ['$cookies', function($cookies) {

      return {
        /**
         * @ngdoc method
         * @name angular.module.ngCookies.$cookieStore#get
         * @methodOf angular.module.ngCookies.$cookieStore
         *
         * @description
         * Returns the value of given cookie key
         *
         * @param {string} key Id to use for lookup.
         * @returns {Object} Deserialized cookie value.
         */
        get: function(key) {
          return angular.fromJson($cookies[key]);
        },

        /**
         * @ngdoc method
         * @name angular.module.ngCookies.$cookieStore#put
         * @methodOf angular.module.ngCookies.$cookieStore
         *
         * @description
         * Sets a value for given cookie key
         *
         * @param {string} key Id for the `value`.
         * @param {Object} value Value to be stored.
         */
        put: function(key, value) {
          $cookies[key] = angular.toJson(value);
        },

        /**
         * @ngdoc method
         * @name angular.module.ngCookies.$cookieStore#remove
         * @methodOf angular.module.ngCookies.$cookieStore
         *
         * @description
         * Remove given cookie
         *
         * @param {string} key Id of the key-value pair to delete.
         */
        remove: function(key) {
          delete $cookies[key];
        }
      };

    }]);
<|endoftext|>


<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 */

define({
    /**
     * Errors
     */

    // General file io error strings
    "GENERIC_ERROR" : "(feil {0})",
    "NOT_FOUND_ERR" : "Kunne ikke finne filen.",
    "NOT_READABLE_ERR" : "Filen kunne ikke bli lest.",
    "NO_MODIFICATION_ALLOWED_ERR" : "Målkatalogen kunnet ikke bli modifisert.",
    "NO_MODIFICATION_ALLOWED_ERR_FILE" : "Rettighetene tillater ikke modifikasjoner.",

    // Project error strings
    "ERROR_LOADING_PROJECT" : "Feil ved lasting av prosjektet",
    "OPEN_DIALOG_ERROR" : "Det oppstod en feil ved forsøk på å åpne fildialog. (feil {0})",
    "REQUEST_NATIVE_FILE_SYSTEM_ERROR" : "Det oppstod en feil ved forsøk på å laste katalogen {0}. (feil {1})",
    "READ_DIRECTORY_ENTRIES_ERROR" : "Det oppstod en feil ved lesing av innholdet i katalogen {0}. (feil {1})",

    // File open/save error string
    "ERROR_OPENING_FILE_TITLE" : "Feil ved åpning av filen",
    "ERROR_OPENING_FILE" : "Det oppstod en feil ved forsøk på å åpne filen {0}. {1}",
    "ERROR_RELOADING_FILE_TITLE" : "Feil ved oppfriskning av endringer fra disk",
    "ERROR_RELOADING_FILE" : "Det oppstod en feil ved forsøk på å oppfriske filen {0}. {1}",
    "ERROR_SAVING_FILE_TITLE" : "Feil ved lagring av fil",
    "ERROR_SAVING_FILE" : "Det oppstod en feil ved forsøk på å lagre filen {0}. {1}",
    "INVALID_FILENAME_TITLE" : "Ugyldig filnavn",
    "INVALID_FILENAME_MESSAGE" : "Filnavn kan ikke inneholde følgende tegn: /?*:;{}<>\\|",
    "FILE_ALREADY_EXISTS" : "Filen {0} eksisterer allerede.",
    "ERROR_CREATING_FILE_TITLE" : "Feil ved oppretting av fil",
    "ERROR_CREATING_FILE" : "Det oppstod en feil ved forsøk på å opprette filen {0}. {1}",

    // Application error strings
    "ERROR_IN_BROWSER_TITLE" : "Oops! {APP_NAME} kjører ikke i nettlesere ennå.",
    "ERROR_IN_BROWSER" : "{APP_NAME} er bygd med HTML, men akkurat nå kjører den som en skrivebords-app slik at du kan bruke den til å redigere lokale filer. Vennligst bruk applikasjonsskallet github.com/adobe/brackets-app repo'et for å kjøre {APP_NAME}",

    // FileIndexManager error string
    "ERROR_MAX_FILES_TITLE" : "Feil ved indeksering av filer",
    "ERROR_MAX_FILES" : "Maksimalt antall filer har blitt indeksert. Handlinger som slår opp filer i indeksen kan feile.",

    // CSSManager error strings
    "ERROR_PARSE_TITLE" : "Feil ved analysering av fil(er):",

    // Live Development error strings
    "ERROR_LAUNCHING_BROWSER_TITLE" : "Feil ved åpning av nettleser",
    "ERROR_CANT_FIND_CHROME" : "Nettleseren Google Chrome ble ikke funnet. Vennligst sørg for at den er installert.",
    "ERROR_LAUNCHING_BROWSER" : "En feil skjedde ved åpning av Nettleseren. (feil {0})",

    "LIVE_DEVELOPMENT_ERROR_TITLE" : "Live Preview feil",
    "LIVE_DEVELOPMENT_RELAUNCH_TITLE"   : "Kobler til nettleser",
    "LIVE_DEVELOPMENT_ERROR_MESSAGE" : "En live development kobling til Chrome kunne ikke bli etablert. For at live development ska fungere må Chrome startes med remote debugging på.

Ønsker du å start Chrome på nytt med remote debugging slått på?",
    "LIVE_DEV_NEED_HTML_MESSAGE" : "Åpne en HTML-fil for å åpne live forhåndsvisning.",
    "LIVE_DEVELOPMENT_INFO_TITLE"       : "Velkommen til Live Preview!",
    "LIVE_DEVELOPMENT_INFO_MESSAGE"     : "Live Preview kobler {APP_NAME} til din nettleser. Den åpner en forhåndsvisning av HTML-filen i nettleseren. Forhåndsvisningen oppdateres umiddelbart når du redigerer koden.

I denne tidlige versjonen av {APP_NAME} fungerer Live Ptrview bare for endringer av CSS-filer og bare med Google Chrome. Vi ønsker å implementere det for HTML og JavaScript også snart!

 (Du ser bare denne meldingen en gang).",

    "LIVE_DEV_STATUS_TIP_NOT_CONNECTED" : "Live File forhåndsvisning",
    "LIVE_DEV_STATUS_TIP_PROGRESS1" : "Live File forhåndsvisning: Kobler...",
    "LIVE_DEV_STATUS_TIP_PROGRESS2" : "Live File forhåndsvisning: Initaliserer...",
    "LIVE_DEV_STATUS_TIP_CONNECTED" : "Koble fra Live File forhåndsvisning",

    "SAVE_CLOSE_TITLE" : "Lagre endringer",
    "SAVE_CLOSE_MESSAGE" : "Ønsker du å lagre enderinger i dokumentet {0}?",
    "SAVE_CLOSE_MULTI_MESSAGE" : "Ønsker du å lagre enderinger i følgende filer?",
    "EXT_MODIFIED_TITLE" : "Eksterne endringer",
    "EXT_MODIFIED_MESSAGE" : "{0} er blitt endret på disk, men har samtidig ulagrede endringer i {APP_NAME}.

Hvilken versjon ønsker du å beholde?",
    "EXT_DELETED_MESSAGE" : "{0} er blitt slettet på disken, men har ulagrede endringer i {APP_NAME}.

Ønsker du å beholde endringene?",

    // Find, Replace, Find in Files
    "SEARCH_REGEXP_INFO" : "Bruk /re/ syntaks for søk med regulære utrykk",
    "WITH" : "Med",
    "BUTTON_YES" : "Ja",
    "BUTTON_NO" : "Nei",
    "BUTTON_STOP" : "Stop",

    "OPEN_FILE" : "Åpne fil",
    "CHOOSE_FOLDER" : "Velg katalog",

    "RELEASE_NOTES" : "Versjonsmerknader",
    "NO_UPDATE_TITLE" : "Du er oppdatert!",
    "NO_UPDATE_MESSAGE" : "Du kjører den nyeste versjonen av {APP_NAME}.",

    "FIND_IN_FILES_TITLE" : "- {0} {1} i {2} {3}",
    "FIND_IN_FILES_FILE" : "fil",
    "FIND_IN_FILES_FILES" : "filer",
    "FIND_IN_FILES_MATCH" : "treff",
    "FIND_IN_FILES_MATCHES" : "treff",
    "FIND_IN_FILES_MAX" : " (viser kun første {0} treff)",
    "FIND_IN_FILES_FILE_PATH" : "Fil: {0}",
    "FIND_IN_FILES_LINE" : "linje: {0}",

    "ERROR_FETCHING_UPDATE_INFO_TITLE" : "Feil ved henting av oppdatering info",
    "ERROR_FETCHING_UPDATE_INFO_MSG" : "Det oppstod et problem ved å få informasjon fra serveren. Vennligst sørg for at du er koblet til internett og prøv på nytt.",

    // Switch language
    "LANGUAGE_TITLE" : "Bytt språk",
    "LANGUAGE_MESSAGE" : "Vennligst velg ønsket språk fra listen under:",
    "LANGUAGE_SUBMIT" : "Gjenåpne {APP_NAME}",
    "LANGUAGE_CANCEL" : "Avbryt",

    /**
     * ProjectManager
     */

    "UNTITLED" : "Uten Tittel",

    /**
     * Command Name Constants
     */

    // File menu commands
    "FILE_MENU" : "Fil",
    "CMD_FILE_NEW" : "Ny",
    "CMD_FILE_OPEN" : "Åpne\u2026",
    "CMD_ADD_TO_WORKING_SET" : "Add To Working Set",
    "CMD_OPEN_FOLDER" : "Åpne mappe\u2026",
    "CMD_FILE_CLOSE" : "Lukk",
    "CMD_FILE_CLOSE_ALL" : "Lukk alle",
    "CMD_FILE_SAVE" : "Lagre",
    "CMD_FILE_SAVE_ALL" : "Lagre alle",
    "CMD_LIVE_FILE_PREVIEW" : "Live File forhåndsvisning",
    "CMD_QUIT" : "Avslutt",

    // Edit menu commands
    "EDIT_MENU" : "Rediger",
    "CMD_SELECT_ALL" : "Velg alt",
    "CMD_FIND" : "Finn",
    "CMD_FIND_IN_FILES" : "Finn i filer",
    "CMD_FIND_NEXT" : "Finn neste",
    "CMD_FIND_PREVIOUS" : "Finn forrige",
    "CMD_REPLACE" : "Erstatt",
    "CMD_INDENT" : "Lag innrykk",
    "CMD_UNINDENT" : "Ta bort innrykk",
    "CMD_DUPLICATE" : "Dupliker",
    "CMD_COMMENT" : "Kommenter/utkommenter linjer",
    "CMD_LINE_UP" : "Flytt Linje(r) opp",
    "CMD_LINE_DOWN" : "Move Linje(r) ned",

    // View menu commands
    "VIEW_MENU" : "Vis",
    "CMD_HIDE_SIDEBAR" : "Gjem sidestolpe",
    "CMD_SHOW_SIDEBAR" : "Vis sidestolpe",
    "CMD_INCREASE_FONT_SIZE" : "Større skrift",
    "CMD_DECREASE_FONT_SIZE" : "Mindre skrift",
    "CMD_RESTORE_FONT_SIZE" : "Tilbakestill skriftstørrelse",

    // Navigate menu Commands
    "NAVIGATE_MENU" : "Naviger",
    "CMD_QUICK_OPEN" : "Hurigåpne",
    "CMD_GOTO_LINE" : "Gå til linje",
    "CMD_GOTO_DEFINITION" : "Gå til definisjon",
    "CMD_TOGGLE_QUICK_EDIT" : "Hurigrediger",
    "CMD_QUICK_EDIT_PREV_MATCH" : "Forrige match",
    "CMD_QUICK_EDIT_NEXT_MATCH" : "Neste match",
    "CMD_NEXT_DOC" : "Neste dokument",
    "CMD_PREV_DOC" : "Forrige dokument",

    // Debug menu commands
    "DEBUG_MENU" : "Debug",
    "CMD_REFRESH_WINDOW" : "Oppdater {APP_NAME}",
    "CMD_SHOW_DEV_TOOLS" : "Vis utviklerverktøy",
    "CMD_RUN_UNIT_TESTS" : "Kjør tester",
    "CMD_JSLINT" : "Aktiver JSLint",
    "CMD_SHOW_PERF_DATA" : "Vis ytelsesdata",
    "CMD_NEW_BRACKETS_WINDOW" : "Nytt {APP_NAME} vindu",
    "CMD_SHOW_EXTENSIONS_FOLDER" : "Vis ekstensjoner",
    "CMD_USE_TAB_CHARS" : "Bruk tab karakterer",
    "CMD_SWITCH_LANGUAGE" : "Bytt språk",
    "CMD_CHECK_FOR_UPDATE" : "Se etter oppdateringer",

    // Help menu commands
    "HELP_MENU" : "Hjelp",
    "CMD_ABOUT" : "Om",
    "CMD_FORUM" : "{APP_NAME} forum",

    // Special commands invoked by the native shell
    "CMD_CLOSE_WINDOW" : "Lukk vindu",
    "CMD_ABORT_QUIT" : "Abort lukk",

    // Strings for main-view.html
    "EXPERIMENTAL_BUILD" : "Eksperimentell bygg",
    "JSLINT_ERRORS" : "JSLint feil",
    "SEARCH_RESULTS" : "Søkeresultater",
    "OK" : "OK",
    "DONT_SAVE" : "Ikke lagre",
    "SAVE" : "Lagre",
    "CANCEL" : "Avbryt",
    "RELOAD_FROM_DISK" : "Oppdater fra disk",
    "KEEP_CHANGES_IN_EDITOR" : "Behold endringer i editor",
    "CLOSE_DONT_SAVE" : "Lukk (ikke lagre)",
    "RELAUNCH_CHROME" : "Start Chrome på nytt",
    "ABOUT" : "Om",
    "APP_NAME" : "Brackets",
    "CLOSE" : "Lukk",
    "ABOUT_TEXT_LINE1" : "sprint 14 experimental build ",
    "ABOUT_TEXT_LINE3": "Notices, terms and conditions pertaining to third party software are located at http://www.adobe.com/go/thirdparty/ and incorporated by reference herein.",
    "ABOUT_TEXT_LINE4" : "Documentation and source at https://github.com/adobe/brackets/",
    "UPDATE_NOTIFICATION_TOOLTIP" : "En ny for {APP_NAME} er tilgjengelig! Klikk her for mer informasjon.",
    "UPDATE_AVAILABLE_TITLE" : "Oppdatering er tilgjengelig",
    "UPDATE_MESSAGE" : "Hei, en ny bygg for {APP_NAME} er tilgjengelig. Her er noen av de nye funksjonene:",
    "GET_IT_NOW" : "Hent den nå!"
});
<commit_msg>Misc. improvements<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 */

define({
    /**
     * Errors
     */

    // General file io error strings
    "GENERIC_ERROR" : "(feil {0})",
    "NOT_FOUND_ERR" : "Kunne ikke finne filen.",
    "NOT_READABLE_ERR" : "Filen kunne ikke bli lest.",
    "NO_MODIFICATION_ALLOWED_ERR" : "Målkatalogen kunnet ikke bli modifisert.",
    "NO_MODIFICATION_ALLOWED_ERR_FILE" : "Rettighetene tillater ikke modifikasjoner.",

    // Project error strings
    "ERROR_LOADING_PROJECT" : "Feil ved lasting av prosjektet",
    "OPEN_DIALOG_ERROR" : "Det oppstod en feil ved forsøk på å åpne fildialog. (feil {0})",
    "REQUEST_NATIVE_FILE_SYSTEM_ERROR" : "Det oppstod en feil ved forsøk på å laste katalogen {0}. (feil {1})",
    "READ_DIRECTORY_ENTRIES_ERROR" : "Det oppstod en feil ved lesing av innholdet i katalogen {0}. (feil {1})",

    // File open/save error string
    "ERROR_OPENING_FILE_TITLE" : "Feil ved åpning av filen",
    "ERROR_OPENING_FILE" : "Det oppstod en feil ved forsøk på å åpne filen {0}. {1}",
    "ERROR_RELOADING_FILE_TITLE" : "Feil ved oppfriskning av endringer fra disk",
    "ERROR_RELOADING_FILE" : "Det oppstod en feil ved forsøk på å oppfriske filen {0}. {1}",
    "ERROR_SAVING_FILE_TITLE" : "Feil ved lagring av fil",
    "ERROR_SAVING_FILE" : "Det oppstod en feil ved forsøk på å lagre filen {0}. {1}",
    "INVALID_FILENAME_TITLE" : "Ugyldig filnavn",
    "INVALID_FILENAME_MESSAGE" : "Filnavn kan ikke inneholde følgende tegn: /?*:;{}<>\\|",
    "FILE_ALREADY_EXISTS" : "Filen {0} eksisterer allerede.",
    "ERROR_CREATING_FILE_TITLE" : "Feil ved oppretting av fil",
    "ERROR_CREATING_FILE" : "Det oppstod en feil ved forsøk på å opprette filen {0}. {1}",

    // Application error strings
    "ERROR_IN_BROWSER_TITLE" : "Oops! {APP_NAME} kjører ikke i nettlesere ennå.",
    "ERROR_IN_BROWSER" : "{APP_NAME} er bygd med HTML, men akkurat nå kjører den som en skrivebords-app slik at du kan bruke den til å redigere lokale filer. Vennligst bruk applikasjonsskallet github.com/adobe/brackets-app repo'et for å kjøre {APP_NAME}",

    // FileIndexManager error string
    "ERROR_MAX_FILES_TITLE" : "Feil ved indeksering av filer",
    "ERROR_MAX_FILES" : "Maksimalt antall filer har blitt indeksert. Handlinger som slår opp filer i indeksen kan feile.",

    // CSSManager error strings
    "ERROR_PARSE_TITLE" : "Feil ved analysering av fil(er):",

    // Live Development error strings
    "ERROR_LAUNCHING_BROWSER_TITLE" : "Feil ved åpning av nettleser",
    "ERROR_CANT_FIND_CHROME" : "Nettleseren Google Chrome ble ikke funnet. Vennligst sørg for at den er installert.",
    "ERROR_LAUNCHING_BROWSER" : "En feil skjedde ved åpning av Nettleseren. (feil {0})",

    "LIVE_DEVELOPMENT_ERROR_TITLE" : "Live Preview feil",
    "LIVE_DEVELOPMENT_RELAUNCH_TITLE"   : "Kobler til nettleser",
    "LIVE_DEVELOPMENT_ERROR_MESSAGE" : "En live development kobling til Chrome kunne ikke bli etablert. For at live development ska fungere må Chrome startes med remote debugging på.

Ønsker du å start Chrome på nytt med remote debugging slått på?",
    "LIVE_DEV_NEED_HTML_MESSAGE" : "Åpne en HTML-fil for å åpne live forhåndsvisning.",
    "LIVE_DEVELOPMENT_INFO_TITLE"       : "Velkommen til Live Preview!",
    "LIVE_DEVELOPMENT_INFO_MESSAGE"     : "Live Preview kobler {APP_NAME} til din nettleser. Den åpner en forhåndsvisning av HTML-filen i nettleseren. Forhåndsvisningen oppdateres umiddelbart når du redigerer koden.

I denne tidlige versjonen av {APP_NAME} fungerer Live Ptrview bare for endringer av CSS-filer og bare med Google Chrome. Vi ønsker å implementere det for HTML og JavaScript også snart!

 (Du ser bare denne meldingen en gang).",

    "LIVE_DEV_STATUS_TIP_NOT_CONNECTED" : "Live File forhåndsvisning",
    "LIVE_DEV_STATUS_TIP_PROGRESS1" : "Live File forhåndsvisning: Kobler...",
    "LIVE_DEV_STATUS_TIP_PROGRESS2" : "Live File forhåndsvisning: Initaliserer...",
    "LIVE_DEV_STATUS_TIP_CONNECTED" : "Koble fra Live File forhåndsvisning",

    "SAVE_CLOSE_TITLE" : "Lagre endringer",
    "SAVE_CLOSE_MESSAGE" : "Ønsker du å lagre enderinger i dokumentet {0}?",
    "SAVE_CLOSE_MULTI_MESSAGE" : "Ønsker du å lagre enderinger i følgende filer?",
    "EXT_MODIFIED_TITLE" : "Eksterne endringer",
    "EXT_MODIFIED_MESSAGE" : "{0} er blitt endret på disk, men har samtidig ulagrede endringer i {APP_NAME}.

Hvilken versjon ønsker du å beholde?",
    "EXT_DELETED_MESSAGE" : "{0} er blitt slettet på disken, men har ulagrede endringer i {APP_NAME}.

Ønsker du å beholde endringene?",

    // Find, Replace, Find in Files
    "SEARCH_REGEXP_INFO" : "Bruk /re/ syntaks for søk med regulære utrykk",
    "WITH" : "Med",
    "BUTTON_YES" : "Ja",
    "BUTTON_NO" : "Nei",
    "BUTTON_STOP" : "Stop",

    "OPEN_FILE" : "Åpne fil",
    "CHOOSE_FOLDER" : "Velg katalog",

    "RELEASE_NOTES" : "Versjonsmerknader",
    "NO_UPDATE_TITLE" : "Du er oppdatert!",
    "NO_UPDATE_MESSAGE" : "Du kjører den nyeste versjonen av {APP_NAME}.",

    "FIND_IN_FILES_TITLE" : "- {0} {1} i {2} {3}",
    "FIND_IN_FILES_FILE" : "fil",
    "FIND_IN_FILES_FILES" : "filer",
    "FIND_IN_FILES_MATCH" : "treff",
    "FIND_IN_FILES_MATCHES" : "treff",
    "FIND_IN_FILES_MAX" : " (viser kun første {0} treff)",
    "FIND_IN_FILES_FILE_PATH" : "Fil: {0}",
    "FIND_IN_FILES_LINE" : "linje: {0}",

    "ERROR_FETCHING_UPDATE_INFO_TITLE" : "Feil ved henting av oppdatering info",
    "ERROR_FETCHING_UPDATE_INFO_MSG" : "Det oppstod et problem ved å få informasjon fra serveren. Vennligst sørg for at du er koblet til internett og prøv på nytt.",

    // Switch language
    "LANGUAGE_TITLE" : "Bytt språk",
    "LANGUAGE_MESSAGE" : "Velg ønsket språk fra listen under:",
    "LANGUAGE_SUBMIT" : "Gjenåpne {APP_NAME}",
    "LANGUAGE_CANCEL" : "Avbryt",

    /**
     * ProjectManager
     */

    "UNTITLED" : "Uten Tittel",

    /**
     * Command Name Constants
     */

    // File menu commands
    "FILE_MENU" : "Fil",
    "CMD_FILE_NEW" : "Ny",
    "CMD_FILE_OPEN" : "Åpne\u2026",
    "CMD_ADD_TO_WORKING_SET" : "Add To Working Set",
    "CMD_OPEN_FOLDER" : "Åpne mappe\u2026",
    "CMD_FILE_CLOSE" : "Lukk",
    "CMD_FILE_CLOSE_ALL" : "Lukk alle",
    "CMD_FILE_SAVE" : "Lagre",
    "CMD_FILE_SAVE_ALL" : "Lagre alle",
    "CMD_LIVE_FILE_PREVIEW" : "Live File forhåndsvisning",
    "CMD_QUIT" : "Avslutt",

    // Edit menu commands
    "EDIT_MENU" : "Rediger",
    "CMD_SELECT_ALL" : "Velg alt",
    "CMD_FIND" : "Finn",
    "CMD_FIND_IN_FILES" : "Finn i filer",
    "CMD_FIND_NEXT" : "Finn neste",
    "CMD_FIND_PREVIOUS" : "Finn forrige",
    "CMD_REPLACE" : "Erstatt",
    "CMD_INDENT" : "Øk innrykk",
    "CMD_UNINDENT" : "Reduser innrykk",
    "CMD_DUPLICATE" : "Dupliker",
    "CMD_COMMENT" : "Kommenter/utkommenter linjer",
    "CMD_LINE_UP" : "Flytt linje(r) opp",
    "CMD_LINE_DOWN" : "Move linje(r) ned",

    // View menu commands
    "VIEW_MENU" : "Vis",
    "CMD_HIDE_SIDEBAR" : "Gjem sidestolpe",
    "CMD_SHOW_SIDEBAR" : "Vis sidestolpe",
    "CMD_INCREASE_FONT_SIZE" : "Større skrift",
    "CMD_DECREASE_FONT_SIZE" : "Mindre skrift",
    "CMD_RESTORE_FONT_SIZE" : "Tilbakestill skriftstørrelse",

    // Navigate menu Commands
    "NAVIGATE_MENU" : "Naviger",
    "CMD_QUICK_OPEN" : "Hurtigåpne",
    "CMD_GOTO_LINE" : "Gå til linje",
    "CMD_GOTO_DEFINITION" : "Gå til definisjon",
    "CMD_TOGGLE_QUICK_EDIT" : "Hurtigrediger",
    "CMD_QUICK_EDIT_PREV_MATCH" : "Forrige match",
    "CMD_QUICK_EDIT_NEXT_MATCH" : "Neste match",
    "CMD_NEXT_DOC" : "Neste dokument",
    "CMD_PREV_DOC" : "Forrige dokument",

    // Debug menu commands
    "DEBUG_MENU" : "Debug",
    "CMD_REFRESH_WINDOW" : "Oppdater {APP_NAME}",
    "CMD_SHOW_DEV_TOOLS" : "Vis utviklerverktøy",
    "CMD_RUN_UNIT_TESTS" : "Kjør tester",
    "CMD_JSLINT" : "Aktiver JSLint",
    "CMD_SHOW_PERF_DATA" : "Vis ytelsesdata",
    "CMD_NEW_BRACKETS_WINDOW" : "Nytt {APP_NAME} vindu",
    "CMD_SHOW_EXTENSIONS_FOLDER" : "Vis ekstensjoner",
    "CMD_USE_TAB_CHARS" : "Bruk tab karakterer",
    "CMD_SWITCH_LANGUAGE" : "Bytt språk",
    "CMD_CHECK_FOR_UPDATE" : "Se etter oppdateringer",

    // Help menu commands
    "HELP_MENU" : "Hjelp",
    "CMD_ABOUT" : "Om",
    "CMD_FORUM" : "{APP_NAME} forum",

    // Special commands invoked by the native shell
    "CMD_CLOSE_WINDOW" : "Lukk vindu",
    "CMD_ABORT_QUIT" : "Abort lukk",

    // Strings for main-view.html
    "EXPERIMENTAL_BUILD" : "Experimental build",
    "JSLINT_ERRORS" : "JSLint feil",
    "SEARCH_RESULTS" : "Søkeresultater",
    "OK" : "OK",
    "DONT_SAVE" : "Ikke lagre",
    "SAVE" : "Lagre",
    "CANCEL" : "Avbryt",
    "RELOAD_FROM_DISK" : "Oppdater fra disk",
    "KEEP_CHANGES_IN_EDITOR" : "Behold endringer i editor",
    "CLOSE_DONT_SAVE" : "Lukk (ikke lagre)",
    "RELAUNCH_CHROME" : "Start Chrome på nytt",
    "ABOUT" : "About",
    "APP_NAME" : "Brackets",
    "CLOSE" : "Lukk",
    "ABOUT_TEXT_LINE1" : "sprint 14 experimental build ",
    "ABOUT_TEXT_LINE3": "Notices, terms and conditions pertaining to third party software are located at http://www.adobe.com/go/thirdparty/ and incorporated by reference herein.",
    "ABOUT_TEXT_LINE4" : "Documentation and source at https://github.com/adobe/brackets/",
    "UPDATE_NOTIFICATION_TOOLTIP" : "En ny for {APP_NAME} er tilgjengelig! Klikk her for mer informasjon.",
    "UPDATE_AVAILABLE_TITLE" : "Oppdatering er tilgjengelig",
    "UPDATE_MESSAGE" : "Hei, en ny bygg for {APP_NAME} er tilgjengelig. Her er noen av de nye funksjonene:",
    "GET_IT_NOW" : "Hent den nå!"
});
<|endoftext|>


<commit_before>import afterMatreshkaInit from '../matreshka/_afterinit';
import addListener from '../on/_addlistener';
import removeListener from '../off/_removelistener';
import triggerOne from '../trigger/_triggerone';
import defs from '../_core/defs';

function changeDelegatedHandler(eventOptions = {}) {
    const { key } = eventOptions;
    const def = defs.get(this);

    if (key && key in def.keys) {
        triggerOne(this, '_asterisk:set', eventOptions);
    }
}

function deleteDelegatedHandler(eventOptions = {}) {
    const { key } = eventOptions;
    const def = defs.get(this);

    if (key && key in def.keys) {
        triggerOne(this, '_asterisk:remove', eventOptions);
    }
}

function changeHandler(eventOptions = {}) {
    const { key, silent } = eventOptions;
    const def = defs.get(this);

    if (key && key in def.keys && !silent) {
        triggerOne(this, 'set', eventOptions);
        triggerOne(this, 'modify', eventOptions);
    }
}

function deleteHandler(eventOptions = {}) {
    const { key, silent } = eventOptions;
    const def = defs.get(this);

    if (key && key in def.keys) {
        delete def.keys[key];

        if (!silent) {
            triggerOne(this, 'remove', eventOptions);
            triggerOne(this, 'modify', eventOptions);
        }
    }
}

export default function afterMatreshkaObjectInit(def) {
    // call "afterinit" of Matreshka
    afterMatreshkaInit.call(this);
    // easy Matreshka.Object detection
    this.isMKObject = true;
    // create a set of data keys
    def.keys = {};

    // trigger asterisk events on the following event
    addListener(this, '_change:delegated', changeDelegatedHandler);

    // trigger asterisk events on the following event
    addListener(this, '_delete:delegated', deleteDelegatedHandler);

    // fire "modify" event when data key is changed
    addListener(this, 'change', changeHandler);

    // fire "modify" and "remove" events when data key is removed
    addListener(this, 'delete', deleteHandler);
}
<commit_msg>add some comments<commit_after>import afterMatreshkaInit from '../matreshka/_afterinit';
import addListener from '../on/_addlistener';
import removeListener from '../off/_removelistener';
import triggerOne from '../trigger/_triggerone';
import defs from '../_core/defs';

// fired on _change:delegated
function changeDelegatedHandler(eventOptions = {}) {
    const { key } = eventOptions;
    const def = defs.get(this);

    if (key && key in def.keys) {
        triggerOne(this, '_asterisk:set', eventOptions);
    }
}

// fired on _delete:delegated
function deleteDelegatedHandler(eventOptions = {}) {
    const { key } = eventOptions;
    const def = defs.get(this);

    if (key && key in def.keys) {
        triggerOne(this, '_asterisk:remove', eventOptions);
    }
}

// fired on change
function changeHandler(eventOptions = {}) {
    const { key, silent } = eventOptions;
    const def = defs.get(this);

    if (key && key in def.keys && !silent) {
        triggerOne(this, 'set', eventOptions);
        triggerOne(this, 'modify', eventOptions);
    }
}

// fired on delete
function deleteHandler(eventOptions = {}) {
    const { key, silent } = eventOptions;
    const def = defs.get(this);

    if (key && key in def.keys) {
        delete def.keys[key];

        if (!silent) {
            triggerOne(this, 'remove', eventOptions);
            triggerOne(this, 'modify', eventOptions);
        }
    }
}

export default function afterMatreshkaObjectInit(def) {
    // call "afterinit" of Matreshka
    afterMatreshkaInit.call(this);
    // easy Matreshka.Object detection
    this.isMKObject = true;
    // create a set of data keys
    def.keys = {};

    // trigger asterisk events
    addListener(this, '_change:delegated', changeDelegatedHandler);

    // trigger asterisk events removal
    addListener(this, '_delete:delegated', deleteDelegatedHandler);

    // fire "modify" and "set" events when data key is changed
    addListener(this, 'change', changeHandler);

    // fire "modify" and "remove" events when data key is removed
    addListener(this, 'delete', deleteHandler);
}
<|endoftext|>