<commit_before>Ext4.define('Kwf.Ext4.Controller.Bindable.Grid', {
    extend: 'Kwf.Ext4.Controller.Bindable.Abstract',

    relation: null,
    gridController: null,
    reloadRowOnSave: false,

    init: function()
    {
    },

    load: function(row)
    {
        var storeName = this.relation+'Store'; //same naming as in Ext.data.association.HasMany
        if (this._loadedRecord && this._loadedRecord[storeName]) {
            //if new row has same id as currently loaded copy the store
            //this makes sures dirty values are kept
            if (row.getId() == this._loadedRecord.getId()) {
                row[storeName] = this._loadedRecord[storeName];
            }
        }
        this._loadedRecord = row;
        var store = row[this.relation]();
        if (!store.loaded) {
            store.loaded = true;
            if (!row.phantom) {
                store.load();
            }
        }
        this.gridController.grid.bindStore(store);
    },

    reset: function()
    {
        this._loadedRecord = null;
        this.gridController.grid.unbindStore();
    },

    isDirty: function()
    {
        if (!this.gridController.grid.getStore()) return false;
        return this.gridController.grid.getStore().getModifiedRecords().length || this.gridController.grid.getStore().getNewRecords().length;
    },

    isValid: function()
    {
        return true;
    },

    _reloadLoadedRow: function()
    {
        var r = this.getLoadedRecord();
        if (!r.phantom) {
            r.self.load(r.getId(), {
                success: function(loadedRow) {
                    r.beginEdit();
                    r.set(loadedRow.getData());
                    r.endEdit();
                    r.commit();
                },
                scope: this
            });
        }
    },

    save: function(syncQueue)
    {
        if (this.gridController.grid.getStore()) {
            if (syncQueue) {
                syncQueue.add(this.gridController.grid.getStore());
                if (this.reloadRowOnSave) {
                    syncQueue.on('finished', function() {
                        this._reloadLoadedRow();

                    }, this, { single: true });
                }
            } else {
                this.gridController.grid.getStore().sync({
                    callback: function() {
                        if (this.reloadRowOnSave) {
                            this._reloadLoadedRow();
                        }
                    },
                    scope: this
                });
            }
        }
    },

    getLoadedRecord: function()
    {
        return this._loadedRecord;
    },

    enable: function()
    {
        this.gridController.grid.enable();
    },
    disable: function()
    {
        this.gridController.grid.disable();
    },
    getPanel: function()
    {
        return this.grid;
    }
});
<commit_msg>Ext4: set parent model when loading HasMany associations<commit_after>Ext4.define('Kwf.Ext4.Controller.Bindable.Grid', {
    extend: 'Kwf.Ext4.Controller.Bindable.Abstract',

    relation: null,
    gridController: null,
    reloadRowOnSave: false,

    init: function()
    {
    },

    load: function(row)
    {
        var storeName = this.relation+'Store'; //same naming as in Ext.data.association.HasMany
        if (this._loadedRecord && this._loadedRecord[storeName]) {
            //if new row has same id as currently loaded copy the store
            //this makes sures dirty values are kept
            if (row.getId() == this._loadedRecord.getId()) {
                row[storeName] = this._loadedRecord[storeName];
            }
        }
        this._loadedRecord = row;
        var store = row[this.relation]();
        if (!store.loaded) {
            store.loaded = true;
            if (!row.phantom) {
                store.load();
            }
        }

        //if both model has HayMany assocication and child model has BelongsTo associacion
        //we set the child models the parent model instance wich they will use for getXxx
        //that way both share the same object
        var belongsToAssoc;
        store.model.prototype.associations.each(function(assoc) {
            if (assoc instanceof Ext4.data.association.BelongsTo) {
                Ext4.ClassManager.get(assoc.model).prototype.associations.each(function(i) {
                    if (i instanceof Ext4.data.association.HasMany
                        && i.model == store.model.$className
                        && i.foreignKey == assoc.foreignKey
                    ) {
                        belongsToAssoc = assoc;
                    }
                }, this);

            }
        }, this);
        if (belongsToAssoc) {
            if (!store['belongsTo'+belongsToAssoc.instanceName]) {
                store.loadRecords = Ext4.Function.createInterceptor(store.loadRecords, function(records) {
                    var store = this;
                    for (var i=0; i < records.length; i++) {
                        records[i][belongsToAssoc.instanceName] = store['belongsTo'+belongsToAssoc.instanceName];
                    }
                });
                store.insert = Ext4.Function.createInterceptor(store.insert, function(index, records) {
                    var store = this;
                    if (!Ext4.isIterable(records)) {
                        records = [records];
                    }
                    for (var i=0; i < records.length; i++) {
                        records[i][belongsToAssoc.instanceName] = store['belongsTo'+belongsToAssoc.instanceName];
                    }
                });
            }
            store['belongsTo'+belongsToAssoc.instanceName] = row;
            store.each(function(r) {
                r[belongsToAssoc.instanceName] = row;
            }, this);
        }

        this.gridController.grid.bindStore(store);
    },

    reset: function()
    {
        this._loadedRecord = null;
        this.gridController.grid.unbindStore();
    },

    isDirty: function()
    {
        if (!this.gridController.grid.getStore()) return false;
        return this.gridController.grid.getStore().getModifiedRecords().length || this.gridController.grid.getStore().getNewRecords().length;
    },

    isValid: function()
    {
        return true;
    },

    _reloadLoadedRow: function()
    {
        var r = this.getLoadedRecord();
        if (!r.phantom) {
            r.self.load(r.getId(), {
                success: function(loadedRow) {
                    r.beginEdit();
                    r.set(loadedRow.getData());
                    r.endEdit();
                    r.commit();
                },
                scope: this
            });
        }
    },

    save: function(syncQueue)
    {
        if (this.gridController.grid.getStore()) {
            if (syncQueue) {
                syncQueue.add(this.gridController.grid.getStore());
                if (this.reloadRowOnSave) {
                    syncQueue.on('finished', function() {
                        this._reloadLoadedRow();

                    }, this, { single: true });
                }
            } else {
                this.gridController.grid.getStore().sync({
                    callback: function() {
                        if (this.reloadRowOnSave) {
                            this._reloadLoadedRow();
                        }
                    },
                    scope: this
                });
            }
        }
    },

    getLoadedRecord: function()
    {
        return this._loadedRecord;
    },

    enable: function()
    {
        this.gridController.grid.enable();
    },
    disable: function()
    {
        this.gridController.grid.disable();
    },
    getPanel: function()
    {
        return this.grid;
    }
});
<|endoftext|>


<commit_before>var url = phantom.args[0];
var callback_url = phantom.args[1];
var script = phantom.args[2];

if (!url || !script) {
  console.log('ghoulio v2.2');
  console.log('');
  console.log('Usage: ');
  console.log('  ghoulio URL CALLBACK_URL SCRIPT');
  console.log('');
  console.log('Use "resolve()" with SCRIPT to end the session');
  phantom.exit(1);
}

var webpage = require('webpage');
var page = webpage.create();

function callback(message, _callback) {
  if (!callback_url) {
    console.warn('No callback URL specified');
    if (_callback) _callback(null);
    return;
  }
  var message_with_url = { url: url };
  var callback_page = webpage.create();
  callback_page.open(callback_url + '?response=' + encodeURIComponent(JSON.stringify(message)), function(status) {
    if (status !== 'success') console.error(status);
    if (_callback) _callback(status);
  });
}

function handle_success(data) {
  console.log(JSON.stringify(data));
  callback({success: true, data: data, url: page.url}, function() {
    phantom.exit(0);
  });
}

function handle_error(message, info) {
  console.error(message);
  if (info) console.error(info);
  callback({success: false, url: url, error: {message: message, info: info}}, function() {
    phantom.exit(1);
  });
}

function handle_message(message) {
  console.info(JSON.stringify(message));
  callback({message: message, url: page.url});
}

phantom.onError = function(msg, trace) {
  handle_error('SlimerJS error: ' + msg, trace);
};

page.onConsoleMessage = function(msg) {
  if (msg.startsWith('*** EXIT SUCCESS ***')) {
    var data = JSON.parse(msg.substring(20));
    handle_success(data);
  } else if (msg.startsWith('*** EXIT FAILURE ***')) {
    var error = JSON.parse(msg.substring(20));
    handle_error(error);
  } else if (msg.startsWith('*** MESSAGE ***')) {
    var message = JSON.parse(msg.substring(15));
    handle_message(message);
  } else {
    console.log(msg);
  }
};

page.onResourceReceived = function(res) {
  if (res.stage === 'end' && res.status >= 400) {
    handle_error('HTTP Error ' + res.status, res.statusText);
  }
};

page
.open(url)
.then(function(status) {
  if (status !== 'success') {
    handle_error('SlimerJS status: ' + status);
    return;
  }
  page.viewportSize = { width: 680, height: 680 };
  page.evaluate(function(script) {
    try {
      function resolve(data) {
        console.log('*** EXIT SUCCESS ***' + JSON.stringify(data || null));
      }
      function reject(e) {
        console.log('*** EXIT FAILURE ***' + JSON.stringify(e ? e.toString() : null));
      }
      function callback(message) {
        console.log('*** MESSAGE ***' + JSON.stringify(message || null));
      }
      eval(script);
    } catch(e) {
      reject(e);
    }
  }, script);
});
<commit_msg>bump version to 2.3<commit_after>var url = phantom.args[0];
var callback_url = phantom.args[1];
var script = phantom.args[2];

if (!url || !script) {
  console.log('ghoulio v2.3');
  console.log('');
  console.log('Usage: ');
  console.log('  ghoulio URL CALLBACK_URL SCRIPT');
  console.log('');
  console.log('Use "resolve()" with SCRIPT to end the session');
  phantom.exit(1);
}

var webpage = require('webpage');
var page = webpage.create();

function callback(message, _callback) {
  if (!callback_url) {
    console.warn('No callback URL specified');
    if (_callback) _callback(null);
    return;
  }
  var message_with_url = { url: url };
  var callback_page = webpage.create();
  callback_page.open(callback_url + '?response=' + encodeURIComponent(JSON.stringify(message)), function(status) {
    if (status !== 'success') console.error(status);
    if (_callback) _callback(status);
  });
}

function handle_success(data) {
  console.log(JSON.stringify(data));
  callback({success: true, data: data, url: page.url}, function() {
    phantom.exit(0);
  });
}

function handle_error(message, info) {
  console.error(message);
  if (info) console.error(info);
  callback({success: false, url: url, error: {message: message, info: info}}, function() {
    phantom.exit(1);
  });
}

function handle_message(message) {
  console.info(JSON.stringify(message));
  callback({message: message, url: page.url});
}

phantom.onError = function(msg, trace) {
  handle_error('SlimerJS error: ' + msg, trace);
};

page.onConsoleMessage = function(msg) {
  if (msg.startsWith('*** EXIT SUCCESS ***')) {
    var data = JSON.parse(msg.substring(20));
    handle_success(data);
  } else if (msg.startsWith('*** EXIT FAILURE ***')) {
    var error = JSON.parse(msg.substring(20));
    handle_error(error);
  } else if (msg.startsWith('*** MESSAGE ***')) {
    var message = JSON.parse(msg.substring(15));
    handle_message(message);
  } else {
    console.log(msg);
  }
};

page.onResourceReceived = function(res) {
  if (res.stage === 'end' && res.status >= 400) {
    handle_error('HTTP Error ' + res.status, res.statusText);
  }
};

page
.open(url)
.then(function(status) {
  if (status !== 'success') {
    handle_error('SlimerJS status: ' + status);
    return;
  }
  page.viewportSize = { width: 680, height: 680 };
  page.evaluate(function(script) {
    try {
      function resolve(data) {
        console.log('*** EXIT SUCCESS ***' + JSON.stringify(data || null));
      }
      function reject(e) {
        console.log('*** EXIT FAILURE ***' + JSON.stringify(e ? e.toString() : null));
      }
      function callback(message) {
        console.log('*** MESSAGE ***' + JSON.stringify(message || null));
      }
      eval(script);
    } catch(e) {
      reject(e);
    }
  }, script);
});
<|endoftext|>


<commit_before>'use strict'

var test = require('tap').test
var split = require('./')
var callback = require('callback-stream')
var strcb = callback.bind(null, { decodeStrings: false })
var objcb = callback.bind(null, { objectMode: true })

test('split two lines on end', function (t) {
  t.plan(2)

  var input = split()

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['hello', 'world'])
  }))

  input.end('hello\nworld')
})

test('split two lines on two writes', function (t) {
  t.plan(2)

  var input = split()

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['hello', 'world'])
  }))

  input.write('hello')
  input.write('\nworld')
  input.end()
})

test('accumulate multiple writes', function (t) {
  t.plan(2)

  var input = split()

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['helloworld'])
  }))

  input.write('hello')
  input.write('world')
  input.end()
})

test('split using a custom string matcher', function (t) {
  t.plan(2)

  var input = split('~')

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['hello', 'world'])
  }))

  input.end('hello~world')
})

test('split using a custom regexp matcher', function (t) {
  t.plan(2)

  var input = split(/~/)

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['hello', 'world'])
  }))

  input.end('hello~world')
})

test('support an option argument', function (t) {
  t.plan(2)

  var input = split({ highWaterMark: 2 })

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['hello', 'world'])
  }))

  input.end('hello\nworld')
})

test('support a mapper function', function (t) {
  t.plan(2)

  var a = { a: '42' }
  var b = { b: '24' }

  var input = split(JSON.parse)

  input.pipe(objcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, [a, b])
  }))

  input.write(JSON.stringify(a))
  input.write('\n')
  input.end(JSON.stringify(b))
})

test('split lines windows-style', function (t) {
  t.plan(2)

  var input = split()

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['hello', 'world'])
  }))

  input.end('hello\r\nworld')
})

test('splits a buffer', function (t) {
  t.plan(2)

  var input = split()

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['hello', 'world'])
  }))

  input.end(new Buffer('hello\nworld'))
})

test('do not end on undefined', function (t) {
  t.plan(2)

  var input = split(function (line) {})

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, [])
  }))

  input.end(new Buffer('hello\nworld'))
})

test('has destroy method', function (t) {
  t.plan(1)

  var input = split(function (line) {})

  input.on('close', function () {
    t.ok(true, 'close emitted')
    t.end()
  })

  input.destroy()
})

test('support custom matcher and mapper', function (t) {
  t.plan(4)

  var a = { a: '42' }
  var b = { b: '24' }
  var input = split('~', JSON.parse)

  t.equal(input.matcher, '~')
  t.equal(typeof input.mapper, 'function')

  input.pipe(objcb(function (err, list) {
    t.notOk(err, 'no errors')
    t.deepEqual(list, [a, b])
  }))

  input.write(JSON.stringify(a))
  input.write('~')
  input.end(JSON.stringify(b))
})

test('support custom matcher and options', function (t) {
  t.plan(6)

  var input = split('~', { highWaterMark: 1024 })

  t.equal(input.matcher, '~')
  t.equal(typeof input.mapper, 'function')
  t.equal(input._readableState.highWaterMark, 1024)
  t.equal(input._writableState.highWaterMark, 1024)

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['hello', 'world'])
  }))

  input.end('hello~world')
})

test('support mapper and options', function (t) {
  t.plan(6)

  var a = { a: '42' }
  var b = { b: '24' }
  var input = split(JSON.parse, { highWaterMark: 1024 })

  t.ok(input.matcher instanceof RegExp, 'matcher is RegExp')
  t.equal(typeof input.mapper, 'function')
  t.equal(input._readableState.highWaterMark, 1024)
  t.equal(input._writableState.highWaterMark, 1024)

  input.pipe(objcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, [a, b])
  }))

  input.write(JSON.stringify(a))
  input.write('\n')
  input.end(JSON.stringify(b))
})

test('split utf8 chars', function (t) {
  t.plan(2)

  var input = split()

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['烫烫烫', '锟斤拷'])
  }))

  var buf = new Buffer('烫烫烫\r\n锟斤拷', 'utf8')
  for (var i = 0; i < buf.length; ++i) {
    input.write(buf.slice(i, i + 1))
  }
  input.end()
})

test('split utf8 chars 2by2', function (t) {
  t.plan(2)

  var input = split()

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['烫烫烫', '烫烫烫'])
  }))

  var str = '烫烫烫\r\n烫烫烫'
  var buf = new Buffer(str, 'utf8')
  for (var i = 0; i < buf.length; i += 2) {
    input.write(buf.slice(i, i + 2))
  }
  input.end()
})

test('split lines when the \n comes at the end of a chunk', function (t) {
  t.plan(2)

  var input = split()

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['hello', 'world'])
  }))

  input.write('hello\n')
  input.end('world')
})

test('truncated utf-8 char', function (t) {
  t.plan(2)

  var input = split()

  input.pipe(strcb(function (err, list) {
    t.error(err)
    t.deepEqual(list, ['烫' + new Buffer('e7', 'hex').toString()])
  }))

  var str = '烫烫'
  var buf = new Buffer(str, 'utf8')

  input.write(buf.slice(0, 3))
  input.end(buf.slice(3, 4))
})

test('maximum buffer limit', function (t) {
  t.plan(1)

  var input = split({ maxLength: 2 })

  input.pipe(strcb(function (err, list) {
    t.ok(err)
  }))

  input.write('hey')
})

<commit_msg>Delete test.js<commit_after><|endoftext|>


<commit_before>var Board = function(size) {
    this.current_color = Board.BLACK;
    this.size = size;
    this.board = this.create_board(size);
    this.last_move_passed = false;
    this.in_atari = false;
    this.attempted_suicide = false;
};

Board.EMPTY = 0;
Board.BLACK = 1;
Board.WHITE = 2;

Board.prototype.create_board = function(size) {
    var m = [];
    for (var i = 0; i < size; i++) {
        m[i] = [];
        for (var j = 0; j < size; j++)
            m[i][j] = Board.EMPTY;
    }
    return m;
};

Board.prototype.switch_player = function() {
    this.current_color = this.current_color == Board.BLACK ? Board.WHITE : Board.BLACK;
};

Board.prototype.pass = function() {
    if (this.last_move_passed)
        this.end_game();
    this.last_move_passed = true;
    this.switch_player();
};

Board.prototype.end_game = function() {
    console.log("GAME OVER");
};

Board.prototype.play = function(i, j) {
    console.log("Played at " + i + ", " + j);
    this.attempted_suicide = this.in_atari = false;

    if (this.board[i][j] != Board.EMPTY)
        return false;

    var color = this.board[i][j] = this.current_color;
    var captured = [];
    var neighbors = this.get_adjacent_intersections(i, j);
    var atari = false;

    var self = this;
    _.each(neighbors, function(n) {
        var state = self.board[n[0]][n[1]];
        if (state != Board.EMPTY && state != color) {
            var group = self.get_group(n[0], n[1]);
            console.log(group);
            if (group["liberties"] == 0)
                captured.push(group);
            else if (group["liberties"] == 1)
                atari = true;
        }
    });

    // detect suicide
    if (_.isEmpty(captured) && this.get_group(i, j)["liberties"] == 0) {
        this.board[i][j] = Board.EMPTY;
        this.attempted_suicide = true;
        return false;
    }

    var self = this;
    _.each(captured, function(group) {
        _.each(group["stones"], function(stone) {
            self.board[stone[0]][stone[1]] = Board.EMPTY;
        });
    });

    if (atari)
        this.in_atari = true;

    this.last_move_passed = false;
    this.switch_player();
    return true;
};

Board.prototype.get_adjacent_intersections = function(i , j) {
    var neighbors = [];
    if (i > 0)
        neighbors.push([i - 1, j]);
    if (j < this.size - 1)
        neighbors.push([i, j + 1]);
    if (i < this.size - 1)
        neighbors.push([i + 1, j]);
    if (j > 0)
        neighbors.push([i, j - 1]);
    return neighbors;
};

Board.prototype.get_group = function(i, j) {

    var color = this.board[i][j];
    if (color == Board.EMPTY)
        return null;

    var visited = {}; // for O(1) lookups
    var visited_list = []; // for returning
    var queue = [[i, j]];
    var count = 0;

    while (queue.length > 0) {
        var stone = queue.pop();
        if (visited[stone])
            continue;

        var neighbors = this.get_adjacent_intersections(stone[0], stone[1]);
        var self = this;
        _.each(neighbors, function(n) {
            var state = self.board[n[0]][n[1]];
            if (state == Board.EMPTY)
                count++;
            if (state == color)
                queue.push([n[0], n[1]]);
        });

        visited[stone] = true;
        visited_list.push(stone);
    }

    return {
        "liberties": count,
        "stones": visited_list
    };
}
<commit_msg>Annotated board.js with comments<commit_after>var Board = function(size) {
    this.current_color = Board.BLACK;
    this.size = size;
    this.board = this.create_board(size);
    this.last_move_passed = false;
    this.in_atari = false;
    this.attempted_suicide = false;
};

Board.EMPTY = 0;
Board.BLACK = 1;
Board.WHITE = 2;

/*
 * Returns a size x size matrix with all entries initialized to Board.EMPTY
 */
Board.prototype.create_board = function(size) {
    var m = [];
    for (var i = 0; i < size; i++) {
        m[i] = [];
        for (var j = 0; j < size; j++)
            m[i][j] = Board.EMPTY;
    }
    return m;
};

/*
 * Switches the current player
 */
Board.prototype.switch_player = function() {
    this.current_color = this.current_color == Board.BLACK ? Board.WHITE : Board.BLACK;
};

/*
 * At any point in the game, a player can pass and let his opponent play
 */
Board.prototype.pass = function() {
    if (this.last_move_passed)
        this.end_game();
    this.last_move_passed = true;
    this.switch_player();
};

/*
 * Called when the game ends (both players passed)
 */
Board.prototype.end_game = function() {
    console.log("GAME OVER");
};

/*
 * Attempt to place a stone at (i,j). Returns true iff the move was legal
 */
Board.prototype.play = function(i, j) {
    console.log("Played at " + i + ", " + j);
    this.attempted_suicide = this.in_atari = false;

    if (this.board[i][j] != Board.EMPTY)
        return false;

    var color = this.board[i][j] = this.current_color;
    var captured = [];
    var neighbors = this.get_adjacent_intersections(i, j);
    var atari = false;

    var self = this;
    _.each(neighbors, function(n) {
        var state = self.board[n[0]][n[1]];
        if (state != Board.EMPTY && state != color) {
            var group = self.get_group(n[0], n[1]);
            console.log(group);
            if (group["liberties"] == 0)
                captured.push(group);
            else if (group["liberties"] == 1)
                atari = true;
        }
    });

    // detect suicide
    if (_.isEmpty(captured) && this.get_group(i, j)["liberties"] == 0) {
        this.board[i][j] = Board.EMPTY;
        this.attempted_suicide = true;
        return false;
    }

    var self = this;
    _.each(captured, function(group) {
        _.each(group["stones"], function(stone) {
            self.board[stone[0]][stone[1]] = Board.EMPTY;
        });
    });

    if (atari)
        this.in_atari = true;

    this.last_move_passed = false;
    this.switch_player();
    return true;
};

/*
 * Given a board position, returns a list of [i,j] coordinates representing
 * orthagonally adjacent intersections
 */
Board.prototype.get_adjacent_intersections = function(i , j) {
    var neighbors = [];
    if (i > 0)
        neighbors.push([i - 1, j]);
    if (j < this.size - 1)
        neighbors.push([i, j + 1]);
    if (i < this.size - 1)
        neighbors.push([i + 1, j]);
    if (j > 0)
        neighbors.push([i, j - 1]);
    return neighbors;
};

/*
 * Performs a breadth-first search about an (i,j) position to find recursively
 * orthagonally adjacent stones of the same color (stones with which it shares
 * liberties). Returns null for if there is no stone at the specified position,
 * otherwise returns an object with two keys: "liberties", specifying the
 * number of liberties the group has, and "stones", the list of [i,j]
 * coordinates of the group's members.
 */
Board.prototype.get_group = function(i, j) {

    var color = this.board[i][j];
    if (color == Board.EMPTY)
        return null;

    var visited = {}; // for O(1) lookups
    var visited_list = []; // for returning
    var queue = [[i, j]];
    var count = 0;

    while (queue.length > 0) {
        var stone = queue.pop();
        if (visited[stone])
            continue;

        var neighbors = this.get_adjacent_intersections(stone[0], stone[1]);
        var self = this;
        _.each(neighbors, function(n) {
            var state = self.board[n[0]][n[1]];
            if (state == Board.EMPTY)
                count++;
            if (state == color)
                queue.push([n[0], n[1]]);
        });

        visited[stone] = true;
        visited_list.push(stone);
    }

    return {
        "liberties": count,
        "stones": visited_list
    };
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015 The AMP HTML Authors. All Rights Reserved.
 *
 * 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.
 */

import {validateData} from '../3p/3p';
import {writeScript} from '../3p/3p';

/**
 * @param {!Window} global
 * @param {!Object} data
 */
export function capirs(global, data) {
  validateData(data, ['begunAutoPad', 'begunBlockId']);

  global['begun_callbacks'] = {
    lib: {
      init: () => {
        const block = global.document.createElement('div');
        block.id = 'x-' + Math.round(Math.random() * 1e8).toString(36);
        document.body.appendChild(block);

        global['Adf']['banner']['ssp'](block.id, data['params'], {
          'begun-auto-pad': data['begunAutoPad'],
          'begun-block-id': data['begunBlockId'],
        });
      },
    },
    block: {
      draw: feed => {
        const banner = feed['banners']['graph'][0];
        window.context.renderStart({
          width: banner['width'],
          height: banner['height'],
        });
        const reportId = 'capirs-' + banner['banner_id'];
        window.context.reportRenderedEntityIdentifier(reportId);
      },
      unexist: window.context.noContentAvailable,
    },
  };

  writeScript(global, '//ssp.rambler.ru/capirs_async.js');
}
<commit_msg>An additional required file was added for Rambler&Co ad network (#7541)<commit_after>/**
 * Copyright 2015 The AMP HTML Authors. All Rights Reserved.
 *
 * 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.
 */

import {validateData} from '../3p/3p';
import {loadScript} from '../3p/3p';

/**
 * @param {!Window} global
 * @param {!Object} data
 */
export function capirs(global, data) {
  validateData(data, ['begunAutoPad', 'begunBlockId']);

  global['begun_callbacks'] = {
    lib: {
      init: () => {
        const block = global.document.createElement('div');
        block.id = 'x-' + Math.round(Math.random() * 1e8).toString(36);
        document.body.appendChild(block);

        global['Adf']['banner']['ssp'](block.id, data['params'], {
          'begun-auto-pad': data['begunAutoPad'],
          'begun-block-id': data['begunBlockId'],
        });
      },
    },
    block: {
      draw: feed => {
        const banner = feed['banners']['graph'][0];
        window.context.renderStart({
          width: banner['width'],
          height: banner['height'],
        });
        const reportId = 'capirs-' + banner['banner_id'];
        window.context.reportRenderedEntityIdentifier(reportId);
      },
      unexist: window.context.noContentAvailable,
    },
  };

  loadScript(global, '//ssp.rambler.ru/lpdid.js');
  loadScript(global, '//ssp.rambler.ru/capirs_async.js');
}
<|endoftext|>


<commit_before>'use strict'

const subscriptions = new Map()
let globalState = {}

function trigger (target, stack) {
  let link = subscriptions.get(target)
  if (link) {
    stack.forEach((v, k) => link.has(k) && link.get(k).forEach(f => f(target[k])))
  }
}

// TODO: remove set from undo/redo actions (use update instead)
let undoRedo = {
  update (story, i) {
    let stack = story.stack,
        target = story.target
    stack.forEach((val, k) => {
      if (val[i] !== null) {
        target[k] = val[i]
      } else if (k in target) {
        delete target[k]
      }
    })
  }
}

function createStore (name, store = {}) {
  if (!name) throw new Error('boxes needs a name')

  globalState[name] = store
  let history = []
  let hIndex = 0

  function get () {
    return globalState[name]
  }

  function applySet (target, key, fresh) {
    if (target[key] !== fresh) {
      let old = key in target ? target[key] : null
      let stack = new Map().set(key, [old, fresh])
      history[hIndex++] = { target, stack, action: 'update' }
      target[key] = fresh
      trigger(target, stack)
    }
  }

  function set (key, value) {
    if (!key || typeof key !== 'string') {
      throw new Error('setAt requires a string key')
    }
    applySet(globalState[name], key, value)
  }

  function setIn (target, key, value) {
    if (!key || typeof key !== 'string') {
      throw new Error('setIn requires a string key')
    }
    if (!target || typeof target !== 'object') {
      throw new Error('setIn requires a object target')
    }
    applySet(target, key, value)
  }

  function update (props) {
    updateIn(globalState[name], props)
  }

  function updateIn (target, props) {
    if (typeof target !== 'object') throw new Error('update requires a object target')
    if (typeof props !== 'object') throw new Error('update requires a object props')

    let stack = new Map()
    Object.keys(props).forEach(k => {
      let fresh = props[k],
          old = target[k]
      if (old !== fresh) {
        if (fresh !== null) {
          stack.set(k, [old, fresh])
          target[k] = fresh
        } else if (k in target) {
          stack.set(k, [old, fresh])
          delete target[k]
        }
      }
    })

    if (stack.size) {
      history[hIndex++] = { target, stack, action: 'update' }
      trigger(target, stack)
    }
  }

  function clear (prop) {
    clearIn(globalState[name], prop)
  }

  function clearIn (target, prop) {
    let obj = target[prop]
    let stack = new Map()
    if (obj) {
      Object.keys(obj).forEach(k => {
        stack.set(k, [obj[k], null])
        delete obj[k]
      })
    }

    if (stack.size) {
      history[hIndex++] = { target: obj, stack, action: 'update' }
      trigger(obj, stack)
    }
  }

  function prevState () {
    if (hIndex) {
      let story = history[--hIndex]
      undoRedo[story.action](story, 0)
      trigger(story.target, story.stack)
    }
  }

  function nextState () {
    if (history[hIndex]) {
      let story = history[hIndex++]
      undoRedo[story.action](story, 1)
      trigger(story.target, story.stack)
    }
  }

  function subscribe (target, key, action) {
    let map = subscriptions.get(target) || subscriptions.set(target, new Map()).get(target)
    let link = map.get(key) || map.set(key, new Set()).get(key)
    link.add(action)
    return () => link.delete(action)
  }

  function getBox (target) {
    return {
      get () {
        return target
      },
      set (key, value) {
        if (!key || typeof key !== 'string') {
          throw new Error('set requires a string key')
        }
        applySet(target, key, value)
      },
      update (props) {
        updateIn(target, props)
      },
      setIn, updateIn, subscribe, getBox
    }
  }

  return {
    get: get,
    set: set, setIn,
    update, updateIn,
    clear, clearIn,
    getBox,
    prevState, nextState,
    subscribe }
}

function has (store) {
  return globalState[store] ? true : false
}

function remove (store) {
  delete globalState[store]
}

module.exports = { createStore, has, remove }
<commit_msg>refactor undoRedo<commit_after>'use strict'

const subscriptions = new Map()
let globalState = {}

function trigger (target, stack) {
  let link = subscriptions.get(target)
  if (link) {
    stack.forEach((v, k) => link.has(k) && link.get(k).forEach(f => f(target[k])))
  }
}

// TODO: remove set from undo/redo actions (use update instead)
function undoRedo (story, i) {
  let stack = story.stack,
      target = story.target
  stack.forEach((val, k) => {
    if (val[i] !== null) {
      target[k] = val[i]
    } else if (k in target) {
      delete target[k]
    }
  })
  trigger(story.target, story.stack)
}

function createStore (name, store = {}) {
  if (!name) throw new Error('boxes needs a name')

  globalState[name] = store
  let history = []
  let hIndex = 0

  function get () {
    return globalState[name]
  }

  function applySet (target, key, fresh) {
    if (target[key] !== fresh) {
      let old = key in target ? target[key] : null
      let stack = new Map().set(key, [old, fresh])
      history[hIndex++] = { target, stack, action: 'update' }
      target[key] = fresh
      trigger(target, stack)
    }
  }

  function set (key, value) {
    if (!key || typeof key !== 'string') {
      throw new Error('setAt requires a string key')
    }
    applySet(globalState[name], key, value)
  }

  function setIn (target, key, value) {
    if (!key || typeof key !== 'string') {
      throw new Error('setIn requires a string key')
    }
    if (!target || typeof target !== 'object') {
      throw new Error('setIn requires a object target')
    }
    applySet(target, key, value)
  }

  function update (props) {
    updateIn(globalState[name], props)
  }

  function updateIn (target, props) {
    if (typeof target !== 'object') throw new Error('update requires a object target')
    if (typeof props !== 'object') throw new Error('update requires a object props')

    let stack = new Map()
    Object.keys(props).forEach(k => {
      let fresh = props[k],
          old = target[k]
      if (old !== fresh) {
        if (fresh !== null) {
          stack.set(k, [old, fresh])
          target[k] = fresh
        } else if (k in target) {
          stack.set(k, [old, fresh])
          delete target[k]
        }
      }
    })

    if (stack.size) {
      history[hIndex++] = { target, stack, action: 'update' }
      trigger(target, stack)
    }
  }

  function clear (prop) {
    clearIn(globalState[name], prop)
  }

  function clearIn (target, prop) {
    let obj = target[prop]
    let stack = new Map()
    if (obj) {
      Object.keys(obj).forEach(k => {
        stack.set(k, [obj[k], null])
        delete obj[k]
      })
    }

    if (stack.size) {
      history[hIndex++] = { target: obj, stack, action: 'update' }
      trigger(obj, stack)
    }
  }

  function prevState () {
    if (hIndex) {
      let story = history[--hIndex]
      undoRedo(story, 0)
    }
  }

  function nextState () {
    if (history[hIndex]) {
      let story = history[hIndex++]
      undoRedo(story, 1)
    }
  }

  function subscribe (target, key, action) {
    let map = subscriptions.get(target) || subscriptions.set(target, new Map()).get(target)
    let link = map.get(key) || map.set(key, new Set()).get(key)
    link.add(action)
    return () => link.delete(action)
  }

  function getBox (target) {
    return {
      get () {
        return target
      },
      set (key, value) {
        if (!key || typeof key !== 'string') {
          throw new Error('set requires a string key')
        }
        applySet(target, key, value)
      },
      update (props) {
        updateIn(target, props)
      },
      setIn, updateIn, subscribe, getBox
    }
  }

  return {
    get: get,
    set: set, setIn,
    update, updateIn,
    clear, clearIn,
    getBox,
    prevState, nextState,
    subscribe }
}

function has (store) {
  return globalState[store] ? true : false
}

function remove (store) {
  delete globalState[store]
}

module.exports = { createStore, has, remove }
<|endoftext|>


<commit_before>var photos = [];
var started = false;

function getBreadPhotos(){
    $.ajax({
        url: "https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=0262b62c1e3dda3b26823024875e2bc1&text=bread&format=json&nojsoncallback=1&sort=relevance&content_type=1&extras=url_o,url_l&license=1,2,3,4,5,6,7",
        success: function(data){
            for(var i=0; i < data.photos.photo.length; i++){
                var photo = data.photos.photo[i];
                var url;
                if(photo.url_o)
                    url = photo.url_o;
                else if(photo.url_l)
                    url = photo.url_l;
                else // an image for ants, skip it
                    continue;

                var link = "https://www.flickr.com/photos/" + photo.owner + "/" + photo.id;

                // preload in cache, if 200 then we can add it to the global photos array
                var img = $("");
                img.on("load", {url:url, link:link}, function(e){

                    photos.push(e.data);
                    if(!started){
                        started = true;
                        showNext();
                    }
                });
                img.attr("src", url);
            }
        },
    });
}

function randomTransform(){
    var transform = "scale(" + (1 + Math.random()*0.3 + 0.2) + ") ";
    transform += "translateX(" + (5-Math.floor(Math.random()*10)) + "%) ";
    transform += "translateY(" + (5-Math.floor(Math.random()*10)) + "%) ";
    return transform;
}

function showNext(){
    var photo = photos.pop();
    photos.unshift(photo);

    var stalebread = $(".bread");
    var newbread = $("
");
    newbread.css("background-image", "url("+photo.url+")");
    newbread.on("transitionend", transitionend);
    stalebread.removeClass("new");
    $(document.body).append(newbread);
    stalebread.addClass("stale");
    newbread.css("transform", randomTransform());
    var _ = newbread[0].offsetTop; //trigger layout
    newbread.removeClass("new");
    newbread.css("transform", randomTransform());

    $("a#source").attr("href", photo.link);
}

function transitionend(e){
    if(e.propertyName == "opacity")
        $(e.target).remove();
    if(e.propertyName == "transform")
        showNext();
}

$(getBreadPhotos);
<commit_msg>perf: don't create a hundred identical functions<commit_after>var photos = [];
var started = false;

function acknowledgeBread(e){
    photos.push(e.data);
    if(!started){
        started = true;
        showNext();
    }
}

function getBreadPhotos(){
    $.ajax({
        url: "https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=0262b62c1e3dda3b26823024875e2bc1&text=bread&format=json&nojsoncallback=1&sort=relevance&content_type=1&extras=url_o,url_l&license=1,2,3,4,5,6,7",
        success: function(data){
            for(var i=0; i < data.photos.photo.length; i++){
                var photo = data.photos.photo[i];
                var url;
                if(photo.url_o)
                    url = photo.url_o;
                else if(photo.url_l)
                    url = photo.url_l;
                else // an image for ants, skip it
                    continue;

                var link = "https://www.flickr.com/photos/" + photo.owner + "/" + photo.id;

                // preload in cache, if 200 then we can add it to the global photos array
                var img = $("");
                img.on("load", {url:url, link:link}, acknowledgeBread);
                img.attr("src", url);
            }
        },
    });
}

function randomTransform(){
    var transform = "scale(" + (1 + Math.random()*0.3 + 0.2) + ") ";
    transform += "translateX(" + (5-Math.floor(Math.random()*10)) + "%) ";
    transform += "translateY(" + (5-Math.floor(Math.random()*10)) + "%) ";
    return transform;
}

function showNext(){
    var photo = photos.pop();
    photos.unshift(photo);

    var stalebread = $(".bread");
    var newbread = $("
");
    newbread.css("background-image", "url("+photo.url+")");
    newbread.on("transitionend", transitionend);
    stalebread.removeClass("new");
    $(document.body).append(newbread);
    stalebread.addClass("stale");
    newbread.css("transform", randomTransform());
    var _ = newbread[0].offsetTop; //trigger layout
    newbread.removeClass("new");
    newbread.css("transform", randomTransform());

    $("a#source").attr("href", photo.link);
}

function transitionend(e){
    if(e.propertyName == "opacity")
        $(e.target).remove();
    if(e.propertyName == "transform")
        showNext();
}

$(getBreadPhotos);
<|endoftext|>


<commit_before>var ModelUpdateNothing = 0
var ModelUpdateInsert = 1
var ModelUpdateUpdate = 2

var ModelUpdateRange = function(type, length) {
	this.type = type
	this.length = length
}

exports.ModelUpdate = function() {
	this.count = 0
	this._reset()
}
exports.ModelUpdate.prototype.constructor = exports.ModelUpdate

exports.ModelUpdate.prototype._reset = function() {
	this._ranges = [new ModelUpdateRange(ModelUpdateNothing, this.count)]
	this._updateIndex = this.count
}

exports.ModelUpdate.prototype._setUpdateIndex = function(begin) {
	if (begin < this._updateIndex)
		this._updateIndex = begin
}

exports.ModelUpdate.prototype._find = function(index) {
	var ranges = this._ranges
	var i
	for(i = 0; i < ranges.length; ++i) {
		var range = ranges[i]
		if (index < range.length)
			return { index: i, offset: index }
		if (range.length > 0)
			index -= range.length
	}
	if (index != 0)
		throw new Error('invalid index ' + index)

	return { index: i - 1, offset: 0 }
}

exports.ModelUpdate.prototype.reset = function(model) {
	this.update(model, 0, Math.min(model.count, this.count))
	if (this.count < model.count) {
		this.insert(model, this.count, model.count)
	} else {
		this.remove(model, model.count, this.count)
	}
}

exports.ModelUpdate.prototype._merge = function() {
	var ranges = this._ranges
	var n = ranges.length - 1
	for(var index = 0; index < n; ) {
		var range = ranges[index]
		var nextRange = ranges[index + 1]
		if (range.type === nextRange) {
			range.length += nextRange.length
			ranges.splice(index + 1, 1)
		} else
			++index
	}
}

exports.ModelUpdate.prototype._split = function(index, offset, type, length) {
	var ranges = this._ranges
	if (offset == 0) {
		ranges.splice(index, 0, new ModelUpdateRange(type, length))
		return index + 1
	} else {
		var range = ranges[index]
		var right = range.length - offset
		range.length = offset
		if (right != 0) {
			ranges.splice(index + 1, 0,
				new ModelUpdateRange(type, length),
				new ModelUpdateRange(range.type, right))
			return index + 2
		} else {
			ranges.splice(index, 0,
				new ModelUpdateRange(type, length))
			return index + 1
		}
	}
}

exports.ModelUpdate.prototype.insert = function(model, begin, end) {
	if (begin >= end)
		return

	this._setUpdateIndex(begin)
	var ranges = this._ranges
	var d = end - begin
	this.count += d
	if (this.count != model.count)
		throw new Error('unbalanced insert ' + this.count + ' + [' + begin + '-' + end + '], model reported ' + model.count)

	var res = this._find(begin)
	var range = ranges[res.index]
	if (range.length == 0) { //first insert
		range.type = ModelUpdateInsert
		range.length += d
	} else if (range.type == ModelUpdateInsert) {
		range.length += d
	} else {
		this._split(res.index, res.offset, ModelUpdateInsert, d)
	}
	this._merge()
}

exports.ModelUpdate.prototype.remove = function(model, begin, end) {
	if (begin >= end)
		return

	this._setUpdateIndex(begin)
	var ranges = this._ranges
	var d = end - begin
	this.count -= d
	if (this.count != model.count)
		throw new Error('unbalanced remove ' + this.count + ' + [' + begin + '-' + end + '], model reported ' + model.count)

	var res = this._find(begin)
	var range = ranges[res.index]
	if (range.type == ModelUpdateInsert) {
		range.length -= d
	} else {
		var index = this._split(res.index, res.offset, ModelUpdateInsert, -d)
		while(d > 0) {
			var range = ranges[index]
			if (range.length <= d) {
				ranges.splice(index, 1)
				d -= ranges.length
			} else {
				range.length -= d
			}
		}
	}
	this._merge()
}

exports.ModelUpdate.prototype.update = function(model, begin, end) {
	if (begin >= end)
		return

	var ranges = this._ranges
	var n = end - begin
	var res = this._find(begin)
	var index = res.index

	var range = ranges[index]
	if (res.offset > 0) {
		ranges.splice(index + 1, 0, new ModelUpdateRange(ModelUpdateNothing, range.length - res.offset))
		range.length = res.offset
		++index
	}

	while(n > 0) {
		var range = ranges[index]
		var length = range.length
		switch(range.type) {
			case ModelUpdateNothing:
				if (length > n) {
					//range larger than needed
					range.length -= n
					ranges.splice(index, 0, new ModelUpdateRange(ModelUpdateUpdate, n))
					n -= length
				} else { //length < n and offset == 0
					range.type = ModelUpdateUpdate
					n -= length
				}
				break
			case ModelUpdateInsert:
				if (length > 0) {
					n -= length
					++index
				}
				break
			case ModelUpdateUpdate:
				n -= length
				++index
				break
		}
	}
	this._merge()
}

exports.ModelUpdate.prototype.apply = function(view) {
	var index = 0
	this._ranges.forEach(
		function(range) {
			switch(range.type) {
				case ModelUpdateInsert:
					var n = range.length
					if (n > 0) {
						view._insertItems(index, index + n)
						index += n
					} else {
						view._removeItems(index, index - n)
					}
					break
				case ModelUpdateUpdate:
					var end = index + range.length
					view._updateItems(index, end)
					index = end
					break
				default:
					index += range.length
			}
		}
	)
	if (view._items.length != this.count)
		throw new Error('unbalanced items update, view: ' + view._items.length + ', update:' + this.count)

	for(var i = this._updateIndex; i < this.count; ++i)
		view._updateDelegateIndex(i)
	this._reset()
}
<commit_msg>fixed typo<commit_after>var ModelUpdateNothing = 0
var ModelUpdateInsert = 1
var ModelUpdateUpdate = 2

var ModelUpdateRange = function(type, length) {
	this.type = type
	this.length = length
}

exports.ModelUpdate = function() {
	this.count = 0
	this._reset()
}
exports.ModelUpdate.prototype.constructor = exports.ModelUpdate

exports.ModelUpdate.prototype._reset = function() {
	this._ranges = [new ModelUpdateRange(ModelUpdateNothing, this.count)]
	this._updateIndex = this.count
}

exports.ModelUpdate.prototype._setUpdateIndex = function(begin) {
	if (begin < this._updateIndex)
		this._updateIndex = begin
}

exports.ModelUpdate.prototype._find = function(index) {
	var ranges = this._ranges
	var i
	for(i = 0; i < ranges.length; ++i) {
		var range = ranges[i]
		if (index < range.length)
			return { index: i, offset: index }
		if (range.length > 0)
			index -= range.length
	}
	if (index != 0)
		throw new Error('invalid index ' + index)

	return { index: i - 1, offset: 0 }
}

exports.ModelUpdate.prototype.reset = function(model) {
	this.update(model, 0, Math.min(model.count, this.count))
	if (this.count < model.count) {
		this.insert(model, this.count, model.count)
	} else {
		this.remove(model, model.count, this.count)
	}
}

exports.ModelUpdate.prototype._merge = function() {
	var ranges = this._ranges
	var n = ranges.length - 1
	for(var index = 0; index < n; ) {
		var range = ranges[index]
		var nextRange = ranges[index + 1]
		if (range.type === nextRange) {
			range.length += nextRange.length
			ranges.splice(index + 1, 1)
		} else
			++index
	}
}

exports.ModelUpdate.prototype._split = function(index, offset, type, length) {
	var ranges = this._ranges
	if (offset == 0) {
		ranges.splice(index, 0, new ModelUpdateRange(type, length))
		return index + 1
	} else {
		var range = ranges[index]
		var right = range.length - offset
		range.length = offset
		if (right != 0) {
			ranges.splice(index + 1, 0,
				new ModelUpdateRange(type, length),
				new ModelUpdateRange(range.type, right))
			return index + 2
		} else {
			ranges.splice(index, 0,
				new ModelUpdateRange(type, length))
			return index + 1
		}
	}
}

exports.ModelUpdate.prototype.insert = function(model, begin, end) {
	if (begin >= end)
		return

	this._setUpdateIndex(begin)
	var ranges = this._ranges
	var d = end - begin
	this.count += d
	if (this.count != model.count)
		throw new Error('unbalanced insert ' + this.count + ' + [' + begin + '-' + end + '], model reported ' + model.count)

	var res = this._find(begin)
	var range = ranges[res.index]
	if (range.length == 0) { //first insert
		range.type = ModelUpdateInsert
		range.length += d
	} else if (range.type == ModelUpdateInsert) {
		range.length += d
	} else {
		this._split(res.index, res.offset, ModelUpdateInsert, d)
	}
	this._merge()
}

exports.ModelUpdate.prototype.remove = function(model, begin, end) {
	if (begin >= end)
		return

	this._setUpdateIndex(begin)
	var ranges = this._ranges
	var d = end - begin
	this.count -= d
	if (this.count != model.count)
		throw new Error('unbalanced remove ' + this.count + ' + [' + begin + '-' + end + '], model reported ' + model.count)

	var res = this._find(begin)
	var range = ranges[res.index]

	if (range.type == ModelUpdateInsert) {
		range.length -= d
	} else {
		var index = this._split(res.index, res.offset, ModelUpdateInsert, -d)
		while(d > 0) {
			var range = ranges[index]
			if (range.length <= d) {
				ranges.splice(index, 1)
				d -= range.length
			} else {
				range.length -= d
			}
		}
	}
	this._merge()
}

exports.ModelUpdate.prototype.update = function(model, begin, end) {
	if (begin >= end)
		return

	var ranges = this._ranges
	var n = end - begin
	var res = this._find(begin)
	var index = res.index

	var range = ranges[index]
	if (res.offset > 0) {
		ranges.splice(index + 1, 0, new ModelUpdateRange(ModelUpdateNothing, range.length - res.offset))
		range.length = res.offset
		++index
	}

	while(n > 0) {
		var range = ranges[index]
		var length = range.length
		switch(range.type) {
			case ModelUpdateNothing:
				if (length > n) {
					//range larger than needed
					range.length -= n
					ranges.splice(index, 0, new ModelUpdateRange(ModelUpdateUpdate, n))
					n -= length
				} else { //length < n and offset == 0
					range.type = ModelUpdateUpdate
					n -= length
				}
				break
			case ModelUpdateInsert:
				if (length > 0) {
					n -= length
					++index
				}
				break
			case ModelUpdateUpdate:
				n -= length
				++index
				break
		}
	}
	this._merge()
}

exports.ModelUpdate.prototype.apply = function(view) {
	var index = 0
	this._ranges.forEach(
		function(range) {
			switch(range.type) {
				case ModelUpdateInsert:
					var n = range.length
					if (n > 0) {
						view._insertItems(index, index + n)
						index += n
					} else {
						view._removeItems(index, index - n)
					}
					break
				case ModelUpdateUpdate:
					var end = index + range.length
					view._updateItems(index, end)
					index = end
					break
				default:
					index += range.length
			}
		}
	)
	if (view._items.length != this.count)
		throw new Error('unbalanced items update, view: ' + view._items.length + ', update:' + this.count)

	for(var i = this._updateIndex; i < this.count; ++i)
		view._updateDelegateIndex(i)
	this._reset()
}
<|endoftext|>


<commit_before>(function () {

    var axisList = { width: [ ], height: [ ] };

    (function () {
        getAxisBreakpoints();
        createActionPanel( );
    })();

    function Breakpoint(mediaSizeSelector) {

        var mediaQuery = initMediaQuery();
        var property = initProperty();
        var propertyAxis = initPropertyAxis();
        var propertyOperator = initPropertyOperator();
        var value = initValue();
        var valueUnit = initValueUnit();
        var valueNumber = initValueNumber();
        var valuePixel = initValuePixel();

        function initMediaQuery() {
            return mediaSizeSelector.split(')')[ 0 ].trim();
        }

        function initProperty() {
            return mediaQuery.split(':')[ 0 ].trim();
        }

        function initPropertyAxis() {
            if (property == 'max-width' || property == 'min-width') {
                return 'width';
            }
            if (property == 'max-height' || property == 'min-height') {
                return 'height';
            }
        }

        function initPropertyOperator() {
            if (property == 'max-height' || property == 'max-width') {
                return 'max';
            }
            if (property == 'min-height' || property == 'min-width') {
                return 'min';
            }
        }

        function initValue() {
            return mediaQuery.split(':')[ 1 ].trim();
        }

        function initValueUnit() {
            return value.replace(/[\d\.]/g, '');
        }

        function initValueNumber() {
            return Number(value.replace(/[^\d\.]/g, ''));
        }

        function initValuePixel() {
            var valuePixel;
            if (valueUnit == 'em') {
                valuePixel = valueNumber * getEmInPxRatio();
            } else if (valueUnit == 'px') {
                valuePixel =  valueNumber;
            }
            if (propertyOperator == 'max') {
                valuePixel++;
            }
            return roundPixel(valuePixel);

            function roundPixel(number) {
                return Math.ceil(number);
            }

            function getEmInPxRatio() {
                var html = document.documentElement;
                var style = html.getAttribute('style');
                html.setAttribute('style', style + ';font-size:1em !important');
                var baseline = parseFloat(getComputedStyle(html).fontSize);
                html.setAttribute('style', style);
                return baseline;
            }
        }

        function getCriticalSize(isSizeBeforeBreakpoint) {
            if (isSizeBeforeBreakpoint) {
                return valuePixel-1;
            }
            return valuePixel;
        }

        function getCriticalSizeEmLabel(isSizeBeforeBreakpoint) {
            if (isSizeBeforeBreakpoint && propertyOperator == 'min') {
                return value+"-";
            }
            if (!isSizeBeforeBreakpoint && propertyOperator == 'max') {
                return value+"+";
            }
            return value;
        }

        return {
            px: valuePixel,
            axis: propertyAxis,
            isValid: function isValid() {
                return ( valuePixel > 0 && typeof( propertyAxis ) != 'undefined' );
            },
            getCriticalSizeShortLabel: function getCriticalSizeShortLabel(isSizeBeforeBreakpoint) {
                if (valueUnit == 'em') {
                    return getCriticalSizeEmLabel(isSizeBeforeBreakpoint);
                }
                return getCriticalSize(isSizeBeforeBreakpoint);
            },
            getCriticalSizeLabel: function getCriticalSizeLabel(isSizeBeforeBreakpoint) {
                if (valueUnit == 'em') {
                    var label = getCriticalSizeEmLabel(isSizeBeforeBreakpoint);
                    return label+" ("+getCriticalSize(isSizeBeforeBreakpoint)+"px)";
                }
                return getCriticalSize(isSizeBeforeBreakpoint)+"px";
            },
            getCriticalSize: getCriticalSize,
            getMediaQuery: function getMediaQuery() {
                return mediaQuery;
            },
            isSizeMatch: function isSizeMatch(size) {
                if (propertyOperator == 'min') {
                    return valuePixel<=size;
                }
                return valuePixel>size;
            }
        };
    };

    function getAxisBreakpoints() {

        var breakpointList = [ ];

        (function () {
            parseCssGetBreakpoints();
            var indexs = { width: [ ], height: [ ] };
            for (var i = 0; i < breakpointList.length; i++) {
                var breakpoint = breakpointList[i];
                if (breakpoint.isValid() && typeof indexs[ breakpoint.axis ][ breakpoint.px ] == 'undefined') {
                    axisList[ breakpoint.axis ].push(breakpoint);
                    indexs[ breakpoint.axis ][ breakpoint.px ] = axisList[ breakpoint.axis ].length - 1;
                }
            }
            axisList.width = axisList.width.sort(function (a, b) {
                return a.px - b.px;
            });
            axisList.height = axisList.height.sort(function (a, b) {
                return a.px - b.px;
            });
        })();

        function parseCssGetBreakpoints() {

            (function () {
                var mediaSelectorList = parseCssGetMediaSelectors();
                for (var i = 0; i < mediaSelectorList.length; i++) {
                    getBreakpointsFromMediaSelector(mediaSelectorList[ i ]);
                }
            })();

            function parseCssGetMediaSelectors() {

                return (function () {
                    var ruleList = parseCssGetRules();
                    var mediaSelectorList = [ ];
                    for (var i = 0; i < ruleList.length; i++) {
                        if (isMediaRule(ruleList[ i ])) {
                            mediaSelectorList.push(ruleList[ i ].media.mediaText);
                        }
                    }
                    return mediaSelectorList;
                })();

                function parseCssGetRules() {
                    var ruleList = [ ];
                    for (var i = 0; i < document.styleSheets.length; i++) {
                        try {
                            for (var j = 0; j < document.styleSheets[ i ].cssRules.length; j++) {
                                ruleList.push(document.styleSheets[ i ].cssRules[ j ]);
                            }
                        } catch (exception) {
                            // External stylesheet
                        }
                    }
                    return ruleList;
                }

                function isMediaRule(rule) {
                    return ( typeof( rule.media ) != 'undefined' );
                }
            }

            function getBreakpointsFromMediaSelector(mediaSelector) {

                (function () {
                    var mediaSelectorPartList = mediaSelector.split('(');
                    for (var i = 1; i < mediaSelectorPartList.length; i++) {
                        if (isMediaRulePartASizeSelector(mediaSelectorPartList[ i ])) {
                            breakpointList.push(Breakpoint(mediaSelectorPartList[ i ]));
                        }
                    }
                })();

                function isMediaRulePartASizeSelector(mediaSelectorPart) {
                    return ( mediaSelectorPart.indexOf(':') != -1 );
                }
            }
        }
    }

    function createActionPanel() {

        var fluidZoneList = { width: [ ], height: [ ] };

        (function () {
            getFluidZonesFromBreakpoints();
            displayFluidZonesActionPanel();
        })();

        function getFluidZonesFromBreakpoints() {

            (function () {
                formatFluidZonesByDirection('width');
                formatFluidZonesByDirection('height');
            })();

            function formatFluidZonesByDirection(direction) {
                if (axisList[ direction ].length != 0) {
                    var previousBreakpoint;
                    for (var i = 0; i < axisList[ direction ].length; i++) {
                        var breakpoint = axisList[ direction ][ i ];
                        var zone = [ ];
                        if (previousBreakpoint == null) {
                            zone.push(null);
                        } else if (previousBreakpoint.px + 1 != breakpoint.px) {
                            zone.push(previousBreakpoint);
                        }
                        zone.push(breakpoint);
                        fluidZoneList[ direction ].push(zone);
                        previousBreakpoint = breakpoint;
                    }
                    fluidZoneList[ direction ].push([ previousBreakpoint, '← ' + direction ]);
                }
            }
        }

        function displayFluidZonesActionPanel() {

            var resizedWindow;

            (function () {
                var panel = createPanelElement();
                if (! panel) {
                    return;
                }
                if (axisList.width.length == 0 && axisList.height.length == 0) {
                    panel.addInformationToPanel('No breakpoint found');
                } else {
                    for (var j = 0; j < fluidZoneList.height.length; j++) {
                        panel.addFluidZoneToPanel('height', fluidZoneList.height[ j ], 'height');
                        panel.addBreakLineToPanel();
                    }
                    panel.addLinktoPanel('Breaq', 'http://tzi.fr/CSS/Responsive/Breaq-bookmarklet', 'See official project page');
                    for (var i = fluidZoneList.width.length-1; i>=0 ; i--) {
                        panel.addFluidZoneToPanel('width', fluidZoneList.width[ i ], 'width');
                    }
                    panel.addBreakLineToPanel();
                }
            })();

            function createPanelElement() {

                var panelElementId = 'BreaqBookmarkletPanel'
                var boxStyle = 'float: right; margin: 0 3px 2px; border: 0; padding: 10px; background: rgba(0, 0, 0, 0.8);';
                var textResetStyle = 'color: white; font-family: Arial, sans-serif;font-weight: normal; font-size: 16px; text-decoration: none;';

                // internal
                var panel = document.getElementById(panelElementId);
                if (panel !== null) {
                    return ;
                }
                panel = document.createElement('div');
                panel.setAttribute('id', panelElementId);
                panel.setAttribute('style', 'position: fixed; bottom:10px; right: 10px; z-index: 999999; text-align: right;');
                document.body.appendChild(panel);

                // private panel methods
                function addPanelElement(element) {
                    element.setAttribute('style', boxStyle+' min-width: 80px; box-sizing: content-box; -moz-box-sizing: content-box; text-align: center; '+textResetStyle);
                    panel.appendChild(element);
                }

                function addInformationToPanel(message) {
                    var information = document.createElement('span');
                    information.innerHTML = message;
                    addPanelElement(information);
                }

                function addLinktoPanel(label, href, title) {
                    link = document.createElement('a');
                    link.setAttribute('href', href);
                    link.setAttribute('target', '_blank');
                    link.setAttribute('title', title);
                    link.innerHTML = label;
                    addPanelElement(link);
                }

                function addBreakLineToPanel() {
                    var br = document.createElement('br');
                    br.setAttribute('style', 'clear: both');
                    panel.appendChild(br);
                }

                // public panel methods
                return {
                    addFluidZoneToPanel: function (direction, zoneBreakpointList, direction) {

                        (function () {
                            var zone = document.createElement('span');
                            zone.innerHTML = ' ';
                            var initialIndex = zoneBreakpointList.length-1;
                            for (var i=initialIndex; i>=0; i--) {
                                var element = createResizeElement(i);
                                if (element) {
                                    panel.appendChild(createResizeElement(i));
                                }
                            }
                        })();

                        function createResizeElement(i) {

                            var element;

                            return (function () {
                                var style = boxStyle+textResetStyle;
                                if (typeof( zoneBreakpointList[ i ] ) == 'object' && zoneBreakpointList[ i ] !== null) {
                                    var isSingleSize = (zoneBreakpointList.length==1);
                                    var isSizeBeforeBreakpoint = (i==1 || isSingleSize);
                                    createResizeButtonElement(zoneBreakpointList[i], isSizeBeforeBreakpoint);
                                    element.innerHTML = zoneBreakpointList[ i ].getCriticalSizeShortLabel(isSizeBeforeBreakpoint);
                                    style += 'border-radius: '+(isSingleSize?'10px':isSizeBeforeBreakpoint?'0 10px 10px 0':'10px 0 0 10px')+';';
                                    if (isSingleSize || isSizeBeforeBreakpoint) {
                                        style += 'margin-right: 0;';
                                    }
                                    if (isSingleSize || !isSizeBeforeBreakpoint) {
                                        style += 'margin-left: 0;';
                                    }
                                } else if (zoneBreakpointList[ i ]) {
                                    createResizeTextElement();
                                    element.innerHTML = zoneBreakpointList[ i ];
                                }
                                if (element) {
                                    element.setAttribute('style', style);
                                    return element;
                                }
                            })();

                            function createResizeTextElement() {
                                element = document.createElement('span');
                            }

                            function createResizeButtonElement(breakpoint, isSizeBeforeBreakpoint) {
                                var targetSize = breakpoint.getCriticalSize(isSizeBeforeBreakpoint);
                                element = document.createElement('a');
                                element.setAttribute('href', 'javascript:;');
                                element.setAttribute('title', 'Resize the '+breakpoint.axis+' to '+breakpoint.getCriticalSizeLabel(isSizeBeforeBreakpoint)+' '+(breakpoint.isSizeMatch(targetSize)?'':'not ')+'to match: '+breakpoint.getMediaQuery());
                                element.addEventListener('click', function () {
                                    var size = { };
                                    var alternate = direction == 'width' ? 'height' : 'width';
                                    var Direction = direction.charAt(0).toUpperCase() + direction.substr(1);
                                    var Alternate = alternate.charAt(0).toUpperCase() + alternate.substr(1);
                                    var existingPopup = ( resizedWindow != null && !resizedWindow.closed );
                                    size[ alternate ] = 600;
                                    if (existingPopup) {
                                        size[ alternate ] = resizedWindow[ 'outer' + Alternate ];
                                        resizedWindow.close();
                                    }
                                    resizedWindow = window.open(window.location + '#', 'resized', 'resizable,scrollbars=1,width=800,height=600');
                                    var resizePopup = function () {
                                        var innerSize;
                                        if (/AppleWebKit/.test(navigator.userAgent)) {
                                            innerSize = resizedWindow.document.documentElement[ 'client' + Direction ];
                                        } else {
                                            innerSize = resizedWindow[ 'inner' + Direction ];
                                        }
                                        size[ direction ] = targetSize + resizedWindow[ 'outer' + Direction ] - innerSize;
                                        resizedWindow.resizeTo(size.width, size.height);
                                        resizedWindow.focus();
                                    };
                                    var interval = setInterval(function () {
                                        if (resizedWindow.document.readyState == 'complete') {
                                            clearInterval(interval);
                                            resizePopup();
                                        }
                                    }, 100);
                                }, false);
                            }
                        }
                    },
                    addInformationToPanel: addInformationToPanel,
                    addLinktoPanel: addLinktoPanel,
                    addBreakLineToPanel: addBreakLineToPanel
                }
            }
        }
    }
})();

<commit_msg>Fix #3: Add a close button<commit_after>(function () {

    var axisList = { width: [ ], height: [ ] };

    (function () {
        getAxisBreakpoints();
        createActionPanel( );
    })();

    function Breakpoint(mediaSizeSelector) {

        var mediaQuery = initMediaQuery();
        var property = initProperty();
        var propertyAxis = initPropertyAxis();
        var propertyOperator = initPropertyOperator();
        var value = initValue();
        var valueUnit = initValueUnit();
        var valueNumber = initValueNumber();
        var valuePixel = initValuePixel();

        function initMediaQuery() {
            return mediaSizeSelector.split(')')[ 0 ].trim();
        }

        function initProperty() {
            return mediaQuery.split(':')[ 0 ].trim();
        }

        function initPropertyAxis() {
            if (property == 'max-width' || property == 'min-width') {
                return 'width';
            }
            if (property == 'max-height' || property == 'min-height') {
                return 'height';
            }
        }

        function initPropertyOperator() {
            if (property == 'max-height' || property == 'max-width') {
                return 'max';
            }
            if (property == 'min-height' || property == 'min-width') {
                return 'min';
            }
        }

        function initValue() {
            return mediaQuery.split(':')[ 1 ].trim();
        }

        function initValueUnit() {
            return value.replace(/[\d\.]/g, '');
        }

        function initValueNumber() {
            return Number(value.replace(/[^\d\.]/g, ''));
        }

        function initValuePixel() {
            var valuePixel;
            if (valueUnit == 'em') {
                valuePixel = valueNumber * getEmInPxRatio();
            } else if (valueUnit == 'px') {
                valuePixel =  valueNumber;
            }
            if (propertyOperator == 'max') {
                valuePixel++;
            }
            return roundPixel(valuePixel);

            function roundPixel(number) {
                return Math.ceil(number);
            }

            function getEmInPxRatio() {
                var html = document.documentElement;
                var style = html.getAttribute('style');
                html.setAttribute('style', style + ';font-size:1em !important');
                var baseline = parseFloat(getComputedStyle(html).fontSize);
                html.setAttribute('style', style);
                return baseline;
            }
        }

        function getCriticalSize(isSizeBeforeBreakpoint) {
            if (isSizeBeforeBreakpoint) {
                return valuePixel-1;
            }
            return valuePixel;
        }

        function getCriticalSizeEmLabel(isSizeBeforeBreakpoint) {
            if (isSizeBeforeBreakpoint && propertyOperator == 'min') {
                return value+"-";
            }
            if (!isSizeBeforeBreakpoint && propertyOperator == 'max') {
                return value+"+";
            }
            return value;
        }

        return {
            px: valuePixel,
            axis: propertyAxis,
            isValid: function isValid() {
                return ( valuePixel > 0 && typeof( propertyAxis ) != 'undefined' );
            },
            getCriticalSizeShortLabel: function getCriticalSizeShortLabel(isSizeBeforeBreakpoint) {
                if (valueUnit == 'em') {
                    return getCriticalSizeEmLabel(isSizeBeforeBreakpoint);
                }
                return getCriticalSize(isSizeBeforeBreakpoint);
            },
            getCriticalSizeLabel: function getCriticalSizeLabel(isSizeBeforeBreakpoint) {
                if (valueUnit == 'em') {
                    var label = getCriticalSizeEmLabel(isSizeBeforeBreakpoint);
                    return label+" ("+getCriticalSize(isSizeBeforeBreakpoint)+"px)";
                }
                return getCriticalSize(isSizeBeforeBreakpoint)+"px";
            },
            getCriticalSize: getCriticalSize,
            getMediaQuery: function getMediaQuery() {
                return mediaQuery;
            },
            isSizeMatch: function isSizeMatch(size) {
                if (propertyOperator == 'min') {
                    return valuePixel<=size;
                }
                return valuePixel>size;
            }
        };
    };

    function getAxisBreakpoints() {

        var breakpointList = [ ];

        (function () {
            parseCssGetBreakpoints();
            var indexs = { width: [ ], height: [ ] };
            for (var i = 0; i < breakpointList.length; i++) {
                var breakpoint = breakpointList[i];
                if (breakpoint.isValid() && typeof indexs[ breakpoint.axis ][ breakpoint.px ] == 'undefined') {
                    axisList[ breakpoint.axis ].push(breakpoint);
                    indexs[ breakpoint.axis ][ breakpoint.px ] = axisList[ breakpoint.axis ].length - 1;
                }
            }
            axisList.width = axisList.width.sort(function (a, b) {
                return a.px - b.px;
            });
            axisList.height = axisList.height.sort(function (a, b) {
                return a.px - b.px;
            });
        })();

        function parseCssGetBreakpoints() {

            (function () {
                var mediaSelectorList = parseCssGetMediaSelectors();
                for (var i = 0; i < mediaSelectorList.length; i++) {
                    getBreakpointsFromMediaSelector(mediaSelectorList[ i ]);
                }
            })();

            function parseCssGetMediaSelectors() {

                return (function () {
                    var ruleList = parseCssGetRules();
                    var mediaSelectorList = [ ];
                    for (var i = 0; i < ruleList.length; i++) {
                        if (isMediaRule(ruleList[ i ])) {
                            mediaSelectorList.push(ruleList[ i ].media.mediaText);
                        }
                    }
                    return mediaSelectorList;
                })();

                function parseCssGetRules() {
                    var ruleList = [ ];
                    for (var i = 0; i < document.styleSheets.length; i++) {
                        try {
                            for (var j = 0; j < document.styleSheets[ i ].cssRules.length; j++) {
                                ruleList.push(document.styleSheets[ i ].cssRules[ j ]);
                            }
                        } catch (exception) {
                            // External stylesheet
                        }
                    }
                    return ruleList;
                }

                function isMediaRule(rule) {
                    return ( typeof( rule.media ) != 'undefined' );
                }
            }

            function getBreakpointsFromMediaSelector(mediaSelector) {

                (function () {
                    var mediaSelectorPartList = mediaSelector.split('(');
                    for (var i = 1; i < mediaSelectorPartList.length; i++) {
                        if (isMediaRulePartASizeSelector(mediaSelectorPartList[ i ])) {
                            breakpointList.push(Breakpoint(mediaSelectorPartList[ i ]));
                        }
                    }
                })();

                function isMediaRulePartASizeSelector(mediaSelectorPart) {
                    return ( mediaSelectorPart.indexOf(':') != -1 );
                }
            }
        }
    }

    function createActionPanel() {

        var fluidZoneList = { width: [ ], height: [ ] };

        (function () {
            getFluidZonesFromBreakpoints();
            displayFluidZonesActionPanel();
        })();

        function getFluidZonesFromBreakpoints() {

            (function () {
                formatFluidZonesByDirection('width');
                formatFluidZonesByDirection('height');
            })();

            function formatFluidZonesByDirection(direction) {
                if (axisList[ direction ].length != 0) {
                    var previousBreakpoint;
                    for (var i = 0; i < axisList[ direction ].length; i++) {
                        var breakpoint = axisList[ direction ][ i ];
                        var zone = [ ];
                        if (previousBreakpoint == null) {
                            zone.push(null);
                        } else if (previousBreakpoint.px + 1 != breakpoint.px) {
                            zone.push(previousBreakpoint);
                        }
                        zone.push(breakpoint);
                        fluidZoneList[ direction ].push(zone);
                        previousBreakpoint = breakpoint;
                    }
                    fluidZoneList[ direction ].push([ previousBreakpoint, '← ' + direction ]);
                }
            }
        }

        function displayFluidZonesActionPanel() {

            var resizedWindow;

            (function () {
                var panel = createPanelElement();
                if (! panel) {
                    return;
                }
                if (axisList.width.length == 0 && axisList.height.length == 0) {
                    panel.addInformationToPanel('No breakpoint found');
                } else {
                    for (var j = 0; j < fluidZoneList.height.length; j++) {
                        panel.addFluidZoneToPanel('height', fluidZoneList.height[ j ], 'height');
                        panel.addBreakLineToPanel();
                    }
                    for (var i = fluidZoneList.width.length-1; i>=0 ; i--) {
                        panel.addFluidZoneToPanel('width', fluidZoneList.width[ i ], 'width');
                    }
                    panel.addBreakLineToPanel();
                }
            })();

            function createPanelElement() {

                var baseElementId = 'BreaqBookmarklet';
                var containerElementId = baseElementId+'Container';
                var controlElementId = baseElementId+'Control';
                var panelElementId = baseElementId+'Panel';
                var boxStyle = 'margin: 0 3px 2px; border: 0; padding: 10px; background: rgba(0, 0, 0, 0.8);';
                var textResetStyle = 'color: white; font-family: Arial, sans-serif;font-weight: normal; font-size: 14px; text-decoration: none;';

                // internal
                var container = document.getElementById(containerElementId);
                if (container !== null) {
                    return ;
                }
                container = document.createElement('div');
                container.setAttribute('id', containerElementId);

                var control = createControlElement();
                container.appendChild(control);

                var panel = createPanelElement();
                container.appendChild(panel);
                document.body.appendChild(container);

                // private panel methods
                function createControlElement() {
                    var control = document.createElement('div');
                    control.setAttribute('id', controlElementId);
                    control.setAttribute('style', 'position: fixed; top:10px; left: 10px; z-index: 999999;');
                    addLinktoPanel('Breaq', 'http://tzi.fr/CSS/Responsive/Breaq-bookmarklet', 'See official project page', control);

                    var closeButton = document.createElement('a');
                    closeButton.setAttribute('href', 'javascript:;');
                    closeButton.setAttribute('title', 'Close BreaqBookmarklet');
                    closeButton.addEventListener('click', function () {
                        var container = document.getElementById(containerElementId);
                        if (container !== null) {
                            container.parentNode.removeChild(container);
                        }
                    }, false);
                    closeButton.innerHTML = 'close';
                    addPanelElement(closeButton, control);

                    return control;
                }

                function createPanelElement() {
                    panel = document.createElement('div');
                    panel.setAttribute('id', panelElementId);
                    panel.setAttribute('style', 'position: fixed; bottom:10px; right: 10px; z-index: 999999;');
                    return panel;
                }

                function addPanelElement(element, parent) {
                    if (typeof parent =='undefined') {
                        parent = panel;
                    }
                    element.setAttribute('style', boxStyle+' display: inline-block; min-width: 80px; box-sizing: content-box; -moz-box-sizing: content-box; text-align: center; '+textResetStyle);
                    parent.appendChild(element);
                }

                function addInformationToPanel(message, parent) {
                    var information = document.createElement('span');
                    information.innerHTML = message;
                    addPanelElement(information, parent);
                }

                function addLinktoPanel(label, href, title, parent) {
                    link = document.createElement('a');
                    link.setAttribute('href', href);
                    link.setAttribute('target', '_blank');
                    link.setAttribute('title', title);
                    link.innerHTML = label;
                    addPanelElement(link, parent);
                }

                function addBreakLineToPanel() {
                    var br = document.createElement('br');
                    br.setAttribute('style', 'clear: both');
                    panel.appendChild(br);
                }

                // public panel methods
                return {
                    addFluidZoneToPanel: function (direction, zoneBreakpointList, direction) {

                        (function () {
                            var zone = document.createElement('span');
                            zone.innerHTML = ' ';
                            var initialIndex = zoneBreakpointList.length-1;
                            for (var i=initialIndex; i>=0; i--) {
                                var element = createResizeElement(i);
                                if (element) {
                                    panel.appendChild(createResizeElement(i));
                                }
                            }
                        })();

                        function createResizeElement(i) {

                            var element;

                            return (function () {
                                var style = boxStyle+' float: right;'+textResetStyle;
                                if (typeof( zoneBreakpointList[ i ] ) == 'object' && zoneBreakpointList[ i ] !== null) {
                                    var isSingleSize = (zoneBreakpointList.length==1);
                                    var isSizeBeforeBreakpoint = (i==1 || isSingleSize);
                                    createResizeButtonElement(zoneBreakpointList[i], isSizeBeforeBreakpoint);
                                    element.innerHTML = zoneBreakpointList[ i ].getCriticalSizeShortLabel(isSizeBeforeBreakpoint);
                                    style += 'border-radius: '+(isSingleSize?'10px':isSizeBeforeBreakpoint?'0 10px 10px 0':'10px 0 0 10px')+';';
                                    if (isSingleSize || isSizeBeforeBreakpoint) {
                                        style += 'margin-right: 0;';
                                    }
                                    if (isSingleSize || !isSizeBeforeBreakpoint) {
                                        style += 'margin-left: 0;';
                                    }
                                } else if (zoneBreakpointList[ i ]) {
                                    createResizeTextElement();
                                    element.innerHTML = zoneBreakpointList[ i ];
                                }
                                if (element) {
                                    element.setAttribute('style', style);
                                    return element;
                                }
                            })();

                            function createResizeTextElement() {
                                element = document.createElement('span');
                            }

                            function createResizeButtonElement(breakpoint, isSizeBeforeBreakpoint) {
                                var targetSize = breakpoint.getCriticalSize(isSizeBeforeBreakpoint);
                                element = document.createElement('a');
                                element.setAttribute('href', 'javascript:;');
                                element.setAttribute('title', 'Resize the '+breakpoint.axis+' to '+breakpoint.getCriticalSizeLabel(isSizeBeforeBreakpoint)+' '+(breakpoint.isSizeMatch(targetSize)?'':'not ')+'to match: '+breakpoint.getMediaQuery());
                                element.addEventListener('click', function () {
                                    var size = { };
                                    var alternate = direction == 'width' ? 'height' : 'width';
                                    var Direction = direction.charAt(0).toUpperCase() + direction.substr(1);
                                    var Alternate = alternate.charAt(0).toUpperCase() + alternate.substr(1);
                                    var existingPopup = ( resizedWindow != null && !resizedWindow.closed );
                                    size[ alternate ] = 600;
                                    if (existingPopup) {
                                        size[ alternate ] = resizedWindow[ 'outer' + Alternate ];
                                        resizedWindow.close();
                                    }
                                    resizedWindow = window.open(window.location + '#', 'resized', 'resizable,scrollbars=1,width=800,height=600');
                                    var resizePopup = function () {
                                        var innerSize;
                                        if (/AppleWebKit/.test(navigator.userAgent)) {
                                            innerSize = resizedWindow.document.documentElement[ 'client' + Direction ];
                                        } else {
                                            innerSize = resizedWindow[ 'inner' + Direction ];
                                        }
                                        size[ direction ] = targetSize + resizedWindow[ 'outer' + Direction ] - innerSize;
                                        resizedWindow.resizeTo(size.width, size.height);
                                        resizedWindow.focus();
                                    };
                                    var interval = setInterval(function () {
                                        if (resizedWindow.document.readyState == 'complete') {
                                            clearInterval(interval);
                                            resizePopup();
                                        }
                                    }, 100);
                                }, false);
                            }
                        }
                    },
                    addInformationToPanel: addInformationToPanel,
                    addLinktoPanel: addLinktoPanel,
                    addBreakLineToPanel: addBreakLineToPanel
                }
            }
        }
    }
})();

<|endoftext|>


<commit_before>var intervals = require('./intervals.js'),
	_ = require('underscore');

_note_dict = {
	'C' : 0,
	'D' : 2,
	'E' : 4,
	'F' : 5,
	'G' : 7,
	'A' : 9,
	'B' : 11
};

fifths = ['F', 'C', 'G', 'D', 'A', 'E', 'B'];

Array.prototype.hasObject = (
	!Array.indexOf ? function (o) {
		var l = this.length + 1;
		while (l -= 1){
			if (this[l - 1] === o) {
				return true;
			}
		}
		return false;
	} : function (o) {
		return (this.indexOf(o) !== -1);
	}
);

function int_to_note(note_int) {
	if(!_.range(0,12).hasObject(note_int)) {
		throw "RangeError: int out of bounds (0-11):" + note_int;
	}
	n = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
	return n[note_int];
}

function is_enharmonic(note1, note2) {
	return note_to_int(note1) == note_to_int(note2);
}

function is_valid_note(note) {
	if(!_note_dict.hasOwnProperty(note[0])) {
		return false;
	}
	var post, _i, _len, _ref;
	_ref = note.slice(1, note.length);
	for(_i = 0, _len = _ref.length; _i < _len; _i++) {
		post = _ref[_i];
		if (post !== 'b' && post !== '#') {
			return false;
		}
	}
	return true;
}

function note_to_int(note) {
	if(is_valid_note(note)) {
		val = _note_dict[note[0]];
	} else {
		throw "NoteFormatError: Unknown note format '" + note + "'";
	}
	var post, _i, _len, _ref;
	_ref = note.slice(1, note.length);
	for(_i = 0, _len = _ref.length; _i < _len; _i++) {
		post = _ref[_i];
		if (post === 'b') {
			val -= 1;
		} else if (post === '#') {
			val += 1;
		}
	}
	return val % 12;
}

function remove_redundant_accidentals(note) {
	var result, token, val, _i, _len, _ref;
	val = 0;
	_ref = note.slice(1, note.length);
	for (_i = 0, _len = _ref.length; _i < _len; _i++) {
		token = _ref[_i];
		if (token === 'b') {
			val -= 1;
		} else if (token === '#') {
			val += 1;
		}
	}

	result = note[0];
	while (val > 0) {
		result = augment(result);
		val -= 1;
	}

	while (val < 0) {
		result = diminish(result);
		val += 1;
	}

	return result;
}

function augment(note) {
	if(note[note.length-1] != 'b') {
		return note + '#';
	} else {
		return note.slice(0, note.length-1);
	}
}

function diminish(note) {
	if(note[note.length-1] != '#') {
		return note + 'b';
	} else {
		return note.slice(0, note.length-1);
	}
}

function to_major(note) {
	return intervals.minor_third(note);
}

function to_minor(note) {
	return intervals.major_sixth(note);
}

//export
exports._note_dict = _note_dict;
exports.fifths = fifths;
exports.int_to_note = int_to_note;
exports.is_enharmonic = is_enharmonic;
exports.is_valid_note = is_valid_note;
exports.note_to_int = note_to_int;
exports.remove_redundant_accidentals = remove_redundant_accidentals;
exports.augment = augment
exports.diminish = diminish;
exports.to_major = to_major;
exports.to_minor = to_minor;<commit_msg>Preparing<commit_after>var intervals = require('./intervals.js'),
	_ = require('underscore');

var _note_dict = {
		'C' : 0,
		'D' : 2,
		'E' : 4,
		'F' : 5,
		'G' : 7,
		'A' : 9,
		'B' : 11
	},
	fifths = ['F', 'C', 'G', 'D', 'A', 'E', 'B'];

Array.prototype.hasObject = (
	!Array.indexOf ? function (o) {
		var l = this.length + 1;
		while (l -= 1){
			if (this[l - 1] === o) {
				return true;
			}
		}
		return false;
	} : function (o) {
		return (this.indexOf(o) !== -1);
	}
);

function int_to_note(note_int) {
	if(!_.range(0,12).hasObject(note_int)) {
		throw "RangeError: int out of bounds (0-11):" + note_int;
	}
	n = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
	return n[note_int];
}

function is_enharmonic(note1, note2) {
	return note_to_int(note1) == note_to_int(note2);
}

function is_valid_note(note) {
	if(!_note_dict.hasOwnProperty(note[0])) {
		return false;
	}
	var post, _i, _len, _ref;
	_ref = note.slice(1, note.length);
	for(_i = 0, _len = _ref.length; _i < _len; _i++) {
		post = _ref[_i];
		if (post !== 'b' && post !== '#') {
			return false;
		}
	}
	return true;
}

function note_to_int(note) {
	if(is_valid_note(note)) {
		val = _note_dict[note[0]];
	} else {
		throw "NoteFormatError: Unknown note format '" + note + "'";
	}
	var post, _i, _len, _ref;
	_ref = note.slice(1, note.length);
	for(_i = 0, _len = _ref.length; _i < _len; _i++) {
		post = _ref[_i];
		if (post === 'b') {
			val -= 1;
		} else if (post === '#') {
			val += 1;
		}
	}
	return val % 12;
}

function remove_redundant_accidentals(note) {
	var result, token, val, _i, _len, _ref;
	val = 0;
	_ref = note.slice(1, note.length);
	for (_i = 0, _len = _ref.length; _i < _len; _i++) {
		token = _ref[_i];
		if (token === 'b') {
			val -= 1;
		} else if (token === '#') {
			val += 1;
		}
	}

	result = note[0];
	while (val > 0) {
		result = augment(result);
		val -= 1;
	}

	while (val < 0) {
		result = diminish(result);
		val += 1;
	}

	return result;
}

function augment(note) {
	if(note[note.length-1] != 'b') {
		return note + '#';
	} else {
		return note.slice(0, note.length-1);
	}
}

function diminish(note) {
	if(note[note.length-1] != '#') {
		return note + 'b';
	} else {
		return note.slice(0, note.length-1);
	}
}

function to_major(note) {
	return intervals.minor_third(note);
}

function to_minor(note) {
	return intervals.major_sixth(note);
}

//export
exports._note_dict = _note_dict;
exports.fifths = fifths;
exports.int_to_note = int_to_note;
exports.is_enharmonic = is_enharmonic;
exports.is_valid_note = is_valid_note;
exports.note_to_int = note_to_int;
exports.remove_redundant_accidentals = remove_redundant_accidentals;
exports.augment = augment
exports.diminish = diminish;
exports.to_major = to_major;
exports.to_minor = to_minor;<|endoftext|>


<commit_before>module.exports.isWebsite = string => {
  return /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/.test(string)
}

module.exports.isEmail = string => {
  return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(string)
}
<commit_msg>Update `isWebsite` validation to use a URL parser<commit_after>module.exports.isWebsite = string => {
  try {
    new URL(string);
    return true;
  } catch (e) {
    // Keeping the regex validation as a fallback to avoid
    // a backwards-incompatible behavior change.
    return /[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/.test(string)
  }
}

module.exports.isEmail = string => {
  return /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(string)
}
<|endoftext|>