<commit_before>/*
 *      This file is part of GPaste.
 *
 *      Copyright 2011 Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
 *
 *      GPaste is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      GPaste is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with GPaste.  If not, see <http://www.gnu.org/licenses/>.
 */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */

const StatusIconDispatcher = imports.ui.statusIconDispatcher;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
const Lang = imports.lang;
const Gio = imports.gi.Gio;
const Pango = imports.gi.Pango;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Gettext = imports.gettext;

const _ = Gettext.domain('GPaste').gettext;
const BUS_NAME = 'org.gnome.GPaste';
const OBJECT_PATH = '/org/gnome/GPaste';

const GPasteInterface =
    <interface name="org.gnome.GPaste">
        <method name="GetHistory">
            <arg type="as" direction="out" />
        </method>
        <method name="Select">
            <arg type="u" direction="in" />
        </method>
        <method name="Delete">
            <arg type="u" direction="in" />
        </method>
        <method name="Empty" />
        <method name="Track">
            <arg type="b" direction="in" />
        </method>
        <signal name="Changed" />
        <signal name="ToggleHistory" />
        <signal name="Tracking">
            <arg type="b" direction="out" />
        </signal>
        <property name="Active" type="b" access="read" />
    </interface>;
const GPasteProxy = Gio.DBusProxy.makeProxyWrapper(GPasteInterface);

function GPasteIndicator() {
    this._init.apply(this, arguments);
}

GPasteIndicator.prototype = {
    __proto__: PanelMenu.SystemStatusButton.prototype,

    _init: function() {
        PanelMenu.SystemStatusButton.prototype._init.call(this, 'edit-paste-symbolic');
        this._killSwitch = new PopupMenu.PopupSwitchMenuItem(_("Track changes"), true);
        this._killSwitch.connect('toggled', Lang.bind(this, this._toggleDaemon));
        this._proxy = new GPasteProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
        this._proxy.connectSignal('Changed', Lang.bind(this, this._fillHistory));
        this._proxy.connectSignal('ToggleHistory', Lang.bind(this, this._toggleHistory));
        this._proxy.connectSignal('Tracking', Lang.bind(this, function(proxy, sender, [trackingState]) {
            this._trackingStateChanged(trackingState);
        }));
        this._createHistory();
        this._emptyHistory = new PopupMenu.PopupMenuItem(_("Empty history"));
        this._emptyHistory.connect('activate', Lang.bind(this, this._empty));
        this._fillMenu();
    },

    _select: function(index) {
        this._proxy.SelectRemote(index);
    },

    _delete: function(index) {
        this._proxy.DeleteRemote(index);
    },

    _empty: function() {
        this._proxy.EmptyRemote();
    },

    _trackingStateChanged: function(trackingState) {
        this._killSwitch.setToggleState(trackingState);
    },

    _toggleDaemon: function() {
        this._proxy.TrackRemote(this._killSwitch.state);
    },

    _fillMenu: function() {
        let active = this._proxy.Active;
        if (active != null)
            this._killSwitch.setToggleState(active);
        this.menu.addMenuItem(this._killSwitch);
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this._addHistoryItems();
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(this._emptyHistory);
        this.menu.addSettingsAction(_("GPaste daemon settings"), 'gpaste-settings.desktop');
        this._fillHistory();
    },

    _fillHistory: function() {
        this._proxy.GetHistoryRemote(Lang.bind(this, function(result, err) {
            let [history] = err ? [null] : result;
            if (history != null && history.length != 0) {
                let limit = Math.min(history.length, this._history.length);
                for (let index = 0; index < limit; ++index)
                    this._updateHistoryItem(index, history[index]);
                this._hideHistory(limit);
                this._emptyHistory.actor.show();
            } else {
                let message = (history == null) ? _("(Couldn't connect to GPaste daemon)") : _("(Empty)");
                this._history[0].updateText(message, message); // TODO: reactive = false
                this._hideHistory();
                this._emptyHistory.actor.hide();
            }
        }));
    },

    _toggleHistory: function() {
        this.menu.toggle();
    },

    _createHistoryItem: function(index) {
        let item = new PopupMenu.PopupAlternatingMenuItem("", "");
        item.actor.style_class = 'my-alternating-menu-item';
        item.actor.add_style_class_name('popup-menu-item');
        let label = item.label;
        label.clutter_text.max_length = 60;
        label.clutter_text.ellipsize = Pango.EllipsizeMode.END;
        item.connect('activate', Lang.bind(this, function(actor, event) {
            if (item.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
                this._select(index);
                return false;
            } else {
                this._delete(index);
                return true;
            }
        }));
        return item;
    },

    _createHistory: function() {
        this._history = [];
        for (let index = 0; index < 20; ++index)
            this._history[index] = this._createHistoryItem(index);
    },

    _addHistoryItems: function() {
        for (let index = 0; index < this._history.length; ++index)
            this.menu.addMenuItem(this._history[index]);
    },

    _updateHistoryItem: function(index, element) {
        let displayStr = element.replace(/\n/g, ' ');
        let altDisplayStr = _("delete: %s").format(displayStr);
        this._history[index].updateText(displayStr, altDisplayStr);
        this._history[index].actor.show();
    },

    _hideHistory: function(startIndex) {
        for (let index = startIndex || 1; index < this._history.length; ++index)
            this._history[index].actor.hide();
    }
};

let _indicator;

function init(metadata) {
    Gettext.bindtextdomain('gpaste', metadata.localedir);
    StatusIconDispatcher.STANDARD_TRAY_ICON_IMPLEMENTATIONS['gpaste-applet'] = 'gpaste';
    Panel.STANDARD_STATUS_AREA_ORDER.unshift('gpaste');
}

function enable() {
    _indicator = new GPasteIndicator();
    Main.panel.addToStatusArea('gpaste', _indicator);
}

function disable() {
    _indicator.destroy();
}

<commit_msg>restore non reactiveness of false history items<commit_after>/*
 *      This file is part of GPaste.
 *
 *      Copyright 2011 Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
 *
 *      GPaste is free software: you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation, either version 3 of the License, or
 *      (at your option) any later version.
 *
 *      GPaste is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with GPaste.  If not, see <http://www.gnu.org/licenses/>.
 */
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */

const StatusIconDispatcher = imports.ui.statusIconDispatcher;
const Main = imports.ui.main;
const Panel = imports.ui.panel;
const Lang = imports.lang;
const Gio = imports.gi.Gio;
const Pango = imports.gi.Pango;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Gettext = imports.gettext;

const _ = Gettext.domain('GPaste').gettext;
const BUS_NAME = 'org.gnome.GPaste';
const OBJECT_PATH = '/org/gnome/GPaste';

const GPasteInterface =
    <interface name="org.gnome.GPaste">
        <method name="GetHistory">
            <arg type="as" direction="out" />
        </method>
        <method name="Select">
            <arg type="u" direction="in" />
        </method>
        <method name="Delete">
            <arg type="u" direction="in" />
        </method>
        <method name="Empty" />
        <method name="Track">
            <arg type="b" direction="in" />
        </method>
        <signal name="Changed" />
        <signal name="ToggleHistory" />
        <signal name="Tracking">
            <arg type="b" direction="out" />
        </signal>
        <property name="Active" type="b" access="read" />
    </interface>;
const GPasteProxy = Gio.DBusProxy.makeProxyWrapper(GPasteInterface);

function GPasteIndicator() {
    this._init.apply(this, arguments);
}

GPasteIndicator.prototype = {
    __proto__: PanelMenu.SystemStatusButton.prototype,

    _init: function() {
        PanelMenu.SystemStatusButton.prototype._init.call(this, 'edit-paste-symbolic');
        this._killSwitch = new PopupMenu.PopupSwitchMenuItem(_("Track changes"), true);
        this._killSwitch.connect('toggled', Lang.bind(this, this._toggleDaemon));
        this._proxy = new GPasteProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
        this._proxy.connectSignal('Changed', Lang.bind(this, this._fillHistory));
        this._proxy.connectSignal('ToggleHistory', Lang.bind(this, this._toggleHistory));
        this._proxy.connectSignal('Tracking', Lang.bind(this, function(proxy, sender, [trackingState]) {
            this._trackingStateChanged(trackingState);
        }));
        this._createHistory();
        this._emptyHistory = new PopupMenu.PopupMenuItem(_("Empty history"));
        this._emptyHistory.connect('activate', Lang.bind(this, this._empty));
        this._fillMenu();
    },

    _select: function(index) {
        this._proxy.SelectRemote(index);
    },

    _delete: function(index) {
        this._proxy.DeleteRemote(index);
    },

    _empty: function() {
        this._proxy.EmptyRemote();
    },

    _trackingStateChanged: function(trackingState) {
        this._killSwitch.setToggleState(trackingState);
    },

    _toggleDaemon: function() {
        this._proxy.TrackRemote(this._killSwitch.state);
    },

    _fillMenu: function() {
        let active = this._proxy.Active;
        if (active != null)
            this._killSwitch.setToggleState(active);
        this.menu.addMenuItem(this._killSwitch);
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this._addHistoryItems();
        this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
        this.menu.addMenuItem(this._emptyHistory);
        this.menu.addSettingsAction(_("GPaste daemon settings"), 'gpaste-settings.desktop');
        this._fillHistory();
    },

    _fillHistory: function() {
        this._proxy.GetHistoryRemote(Lang.bind(this, function(result, err) {
            let [history] = err ? [null] : result;
            if (history != null && history.length != 0) {
                let limit = Math.min(history.length, this._history.length);
                for (let index = 0; index < limit; ++index)
                    this._updateHistoryItem(index, history[index]);
                this._history[0].actor.reactive = true;
                this._hideHistory(limit);
                this._emptyHistory.actor.show();
            } else {
                let message = (history == null) ? _("(Couldn't connect to GPaste daemon)") : _("(Empty)");
                this._history[0].updateText(message, message);
                this._history[0].actor.reactive = false;
                this._hideHistory();
                this._emptyHistory.actor.hide();
            }
        }));
    },

    _toggleHistory: function() {
        this.menu.toggle();
    },

    _createHistoryItem: function(index) {
        let item = new PopupMenu.PopupAlternatingMenuItem("", "");
        item.actor.style_class = 'my-alternating-menu-item';
        item.actor.add_style_class_name('popup-menu-item');
        let label = item.label;
        label.clutter_text.max_length = 60;
        label.clutter_text.ellipsize = Pango.EllipsizeMode.END;
        item.connect('activate', Lang.bind(this, function(actor, event) {
            if (item.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
                this._select(index);
                return false;
            } else {
                this._delete(index);
                return true;
            }
        }));
        return item;
    },

    _createHistory: function() {
        this._history = [];
        for (let index = 0; index < 20; ++index)
            this._history[index] = this._createHistoryItem(index);
    },

    _addHistoryItems: function() {
        for (let index = 0; index < this._history.length; ++index)
            this.menu.addMenuItem(this._history[index]);
    },

    _updateHistoryItem: function(index, element) {
        let displayStr = element.replace(/\n/g, ' ');
        let altDisplayStr = _("delete: %s").format(displayStr);
        this._history[index].updateText(displayStr, altDisplayStr);
        this._history[index].actor.show();
    },

    _hideHistory: function(startIndex) {
        for (let index = startIndex || 1; index < this._history.length; ++index)
            this._history[index].actor.hide();
    }
};

let _indicator;

function init(metadata) {
    Gettext.bindtextdomain('gpaste', metadata.localedir);
    StatusIconDispatcher.STANDARD_TRAY_ICON_IMPLEMENTATIONS['gpaste-applet'] = 'gpaste';
    Panel.STANDARD_STATUS_AREA_ORDER.unshift('gpaste');
}

function enable() {
    _indicator = new GPasteIndicator();
    Main.panel.addToStatusArea('gpaste', _indicator);
}

function disable() {
    _indicator.destroy();
}

<|endoftext|>


<commit_before>export const extend = (matrixOps, overField) => {
  const ops = matrixOps;

  const extendBasis = (v, bs) => {
    const [nrows, ncols] = bs == null ? [0, v.length] : ops.shape(bs);
    if (v.length != ncols)
      throw Error("shapes don't match");

    let rowBs = 0;
    let colBs = 0;
    let colV = 0;

    while (rowBs < nrows && colBs < ncols) {
      const b = bs[rowBs];
      while (colBs < ncols && ops.eq(b[colBs], 0))
        ++colBs;

      while (colV < ncols && ops.eq(v[colV], 0))
        ++colV;

      if (colV < colBs || colV >= ncols || colBs >= ncols)
        break;
      else if (colV == colBs) {
        if (overField || ops.eq(0, ops.mod(v[colV], b[colV]))) {
          v = ops.minus(v, ops.times(b, ops.div(v[colV], b[colV])));
        }
        else {
          const [x, r, s, t, u] = ops.gcdex(b[colV], v[colV]);
          bs[rowBs] = ops.plus(ops.times(b, r), ops.times(v, s));
          if (ops.lt(ops.times(r, u), ops.times(s, t)))
            bs[rowBs] = ops.negative(bs[rowBs]);
          v = ops.plus(ops.times(b, t), ops.times(v, u));
        }
      }

      ++rowBs;
    }

    while (colV < ncols && ops.eq(v[colV], 0))
      ++colV;

    if (colV < ncols) {
      if ((nrows - rowBs) % 2 != 0)
        v = ops.negative(v);

      if (nrows == 0)
        return [v];
      else
        return bs.slice(0, rowBs).concat([v], bs.slice(rowBs));
    }
    else
      return bs;
  };

  const triangularBasis = rows => {
    let bs = null;
    for (const v of rows)
      bs = extendBasis(v, bs);
    return bs;
  };

  const rank = rows => triangularBasis(rows).length;

  const determinant = rows => {
    const [nrows, ncols] = ops.shape(rows);
    if (nrows != ncols)
      throw new Error('must be a square matrix');

    const bs = triangularBasis(rows);

    if (bs.length < nrows)
      return 0;
    else
      return bs.map((v, i) => v[i]).reduce((a, x) => ops.times(a, x));
  };

  const reducedBasis = rows => {
    const div = overField ? ops.div : ops.idiv;
    const bs = triangularBasis(rows);

    let col = 0;
    for (let row = 0; row < bs.length; ++row) {
      while (ops.eq(bs[row][col], 0))
        ++col;

      if (ops.lt(bs[row][col], 0))
        bs[row] = ops.negative(bs[row]);

      if (overField && ops.ne(bs[row][col], 1))
        bs[row] = div(bs[row], bs[row][col]);

      const p = bs[row][col];

      for (let i = 0; i < row; ++i) {
        if (overField || ops.ge(bs[i][col], p) || ops.lt(bs[i][col], 0))
          bs[i] = ops.minus(bs[i], ops.times(bs[row], div(bs[i][col], p)));
      }
    }

    return bs;
  };

  const _solveSingle = (vec, val) => {
    let out = ops.times(vec, 0);

    if (overField)
      out[0] = ops.div(val, vec[0]);
    else if (vec.length == 1) {
      if (ops.eq(ops.mod(val, vec[0]), 0))
        out[0] = ops.div(val, vec[0]);
      else
        out = null;
    }
    else
      console.log('not yet implemented');

    return out;
  };

  const solve = (lft, rgt) => {
    const [rowsLft, colsLft] = ops.shape(lft);
    const [rowsRgt, colsRgt] = ops.shape(rgt);

    if (rowsLft != rowsRgt)
      throw new Error('left and right side must have equal number of rows');

    const bs = reducedBasis(lft.map((v, i) => v.concat(rgt[i])));
    const [rows, cols] = ops.shape(bs);

    const leading = [];
    let col = 0;
    for (let row = 0; row < bs.length; ++row) {
      while (ops.eq(bs[row][col], 0))
        ++col;
      leading.push(col);
    }
    leading.push(colsLft);

    if (leading[rows - 1] >= colsLft)
      return null;

    const result = [];

    for (let j = colsLft; j < cols; ++j) {
      let out = [];

      for (let k = rows - 1; k >= 0; --k) {
        const b = bs[k];
        const [from, to] = [leading[k], leading[k + 1]];
        const v = b.slice(from, to);
        const s = ops.minus(b[j], ops.times(out, b.slice(to, colsLft)));

        const w = _solveSingle(v, s);
        if (w == null)
          return null;
        else
          out = w.concat(out);
      }

      result.push(out);
    }

    return ops.transposed(result);
  };

  const methods = {
    extendBasis: {
      Vector: {
        Null: extendBasis,
        Matrix: extendBasis
      }
    },
    triangularBasis: { Matrix: triangularBasis },
    reducedBasis: { Matrix: reducedBasis },
    rank: { Matrix: rank },
    determinant: { Matrix: determinant },
    solve: { Matrix: { Matrix: solve } }
  };

  return ops.register(methods);
};

if (require.main == module) {
  Array.prototype.toString = function() {
    return '[ ' + this.map(x => x.toString()).join(', ') + ' ]';
  };

  const types = require('./types');
  const opsO = types.rationalMatrices;
  const opsF = extend(types.rationalMatrices, true);
  const opsM = extend(types.rationalMatrices, false);

  const I = [[1,0,0],[0,1,0],[0,0,1]];
  const B = [[1,2,3],[4,5,6],[7,8,0]];

  const testIn = (A, ops) => {
    const [n, m] = opsO.shape(A);

    console.log(`  basis = ${ops.triangularBasis(A)}`);
    console.log(`  reduced = ${ops.reducedBasis(A)}`);
    console.log(`  rank(A): ${opsO.rank(A)} <-> ${ops.rank(A)}`);
    if (n == m)
      console.log(
        `  det(A) : ${opsO.determinant(A)} <-> ${ops.determinant(A)}`);

    const Ainv = ops.solve(A, I);
    if (Ainv)
      console.log(`  inverse check: ${A} * ${Ainv} = ${ops.times(A, Ainv)}`);
    else
      console.log(`  no inverse`);

    const M = ops.solve(A, ops.times(A, B));
    console.log(`  solving ${A} * M = ${ops.times(A, B)}:`);
    console.log(`  M = ${M}`);
    if (M != null)
      console.log(`  check: ${ops.times(A, M)}`);
  };

  const test = A => {
    console.log(`A = ${A}`);
    console.log(`over field:`);
    testIn(A, opsF);
    console.log(`over module:`);
    testIn(A, opsM);
    console.log();
  };

  test([[1,2,3],[0,4,5],[6,0,7]]);
  test([[2,3,4],[5,6,7],[8,9,0]]);
  test([[9,8,7],[6,5,4],[3,2,1]]);
  test([[1,2,3],[0,1,4],[0,0,1]]);
  test([[1,1,1],[0,1,1],[0,0,1]]);
}
<commit_msg>some refactoring in linear equation solver<commit_after>export const extend = (matrixOps, overField) => {
  const ops = matrixOps;

  const extendBasis = (v, bs) => {
    const [nrows, ncols] = bs == null ? [0, v.length] : ops.shape(bs);
    if (v.length != ncols)
      throw Error("shapes don't match");

    let rowBs = 0;
    let colBs = 0;
    let colV = 0;

    while (rowBs < nrows && colBs < ncols) {
      const b = bs[rowBs];
      while (colBs < ncols && ops.eq(b[colBs], 0))
        ++colBs;

      while (colV < ncols && ops.eq(v[colV], 0))
        ++colV;

      if (colV < colBs || colV >= ncols || colBs >= ncols)
        break;
      else if (colV == colBs) {
        if (overField || ops.eq(0, ops.mod(v[colV], b[colV]))) {
          v = ops.minus(v, ops.times(b, ops.div(v[colV], b[colV])));
        }
        else {
          const [x, r, s, t, u] = ops.gcdex(b[colV], v[colV]);
          bs[rowBs] = ops.plus(ops.times(b, r), ops.times(v, s));
          if (ops.lt(ops.times(r, u), ops.times(s, t)))
            bs[rowBs] = ops.negative(bs[rowBs]);
          v = ops.plus(ops.times(b, t), ops.times(v, u));
        }
      }

      ++rowBs;
    }

    while (colV < ncols && ops.eq(v[colV], 0))
      ++colV;

    if (colV < ncols) {
      if ((nrows - rowBs) % 2 != 0)
        v = ops.negative(v);

      if (nrows == 0)
        return [v];
      else
        return bs.slice(0, rowBs).concat([v], bs.slice(rowBs));
    }
    else
      return bs;
  };

  const triangularBasis = rows => {
    let bs = null;
    for (const v of rows)
      bs = extendBasis(v, bs);
    return bs;
  };

  const rank = rows => triangularBasis(rows).length;

  const determinant = rows => {
    const [nrows, ncols] = ops.shape(rows);
    if (nrows != ncols)
      throw new Error('must be a square matrix');

    const bs = triangularBasis(rows);

    if (bs.length < nrows)
      return 0;
    else
      return bs.map((v, i) => v[i]).reduce((a, x) => ops.times(a, x));
  };

  const reducedBasis = rows => {
    const div = overField ? ops.div : ops.idiv;
    const bs = triangularBasis(rows);

    let col = 0;
    for (let row = 0; row < bs.length; ++row) {
      while (ops.eq(bs[row][col], 0))
        ++col;

      if (ops.lt(bs[row][col], 0))
        bs[row] = ops.negative(bs[row]);

      if (overField && ops.ne(bs[row][col], 1))
        bs[row] = div(bs[row], bs[row][col]);

      const p = bs[row][col];

      for (let i = 0; i < row; ++i) {
        if (overField || ops.ge(bs[i][col], p) || ops.lt(bs[i][col], 0))
          bs[i] = ops.minus(bs[i], ops.times(bs[row], div(bs[i][col], p)));
      }
    }

    return bs;
  };

  const _solveDiophantine = (vec, val) => {
    if (vec.length == 1) {
      if (ops.eq(ops.mod(val, vec[0]), 0))
        return [ops.div(val, vec[0])];
      else
        return null;
    }
    else {
      console.log('not yet implemented');
      return null;
    }
  };

  const _leadingPositions = bs => {
    const result = [];
    let col = 0;
    for (let row = 0; row < bs.length; ++row) {
      while (ops.eq(bs[row][col], 0))
        ++col;
      result.push(col);
    }

    return result;
  };

  const solve = (lft, rgt) => {
    const [rowsLft, colsLft] = ops.shape(lft);
    const [rowsRgt, colsRgt] = ops.shape(rgt);

    if (rowsLft != rowsRgt)
      throw new Error('left and right side must have equal number of rows');

    const bs = reducedBasis(lft.map((v, i) => v.concat(rgt[i])));
    const [rows, cols] = ops.shape(bs);
    const leading = _leadingPositions(bs);

    if (leading[rows - 1] >= colsLft)
      return null;

    leading.push(colsLft);

    const result = [];

    for (let j = colsLft; j < cols; ++j) {
      let out = [];

      for (let k = rows - 1; k >= 0; --k) {
        const b = bs[k];
        const [from, to] = [leading[k], leading[k + 1]];
        const s = ops.minus(b[j], ops.times(out, b.slice(to, colsLft)));

        if (overField) {
          out = ops.vector(to - from).concat(out);
          out[0] = ops.div(s, b[from]);
        }
        else {
          const w = _solveDiophantine(b.slice(from, to), s);
          if (w == null)
            return null;
          else
            out = w.concat(out);
        }
      }

      result.push(out);
    }

    return ops.transposed(result);
  };

  const methods = {
    extendBasis: {
      Vector: {
        Null: extendBasis,
        Matrix: extendBasis
      }
    },
    triangularBasis: { Matrix: triangularBasis },
    reducedBasis: { Matrix: reducedBasis },
    rank: { Matrix: rank },
    determinant: { Matrix: determinant },
    solve: { Matrix: { Matrix: solve } }
  };

  return ops.register(methods);
};

if (require.main == module) {
  Array.prototype.toString = function() {
    return '[ ' + this.map(x => x.toString()).join(', ') + ' ]';
  };

  const types = require('./types');
  const opsO = types.rationalMatrices;
  const opsF = extend(types.rationalMatrices, true);
  const opsM = extend(types.rationalMatrices, false);

  const I = [[1,0,0],[0,1,0],[0,0,1]];
  const B = [[1,2,3],[4,5,6],[7,8,0]];

  const testIn = (A, ops) => {
    const [n, m] = opsO.shape(A);

    console.log(`  basis = ${ops.triangularBasis(A)}`);
    console.log(`  reduced = ${ops.reducedBasis(A)}`);
    console.log(`  rank(A): ${opsO.rank(A)} <-> ${ops.rank(A)}`);
    if (n == m)
      console.log(
        `  det(A) : ${opsO.determinant(A)} <-> ${ops.determinant(A)}`);

    const Ainv = ops.solve(A, I);
    if (Ainv)
      console.log(`  inverse check: ${A} * ${Ainv} = ${ops.times(A, Ainv)}`);
    else
      console.log(`  no inverse`);

    const M = ops.solve(A, ops.times(A, B));
    console.log(`  solving ${A} * M = ${ops.times(A, B)}:`);
    console.log(`  M = ${M}`);
    if (M != null)
      console.log(`  check: ${ops.times(A, M)}`);
  };

  const test = A => {
    console.log(`A = ${A}`);
    console.log(`over field:`);
    testIn(A, opsF);
    console.log(`over module:`);
    testIn(A, opsM);
    console.log();
  };

  test([[1,2,3],[0,4,5],[6,0,7]]);
  test([[2,3,4],[5,6,7],[8,9,0]]);
  test([[9,8,7],[6,5,4],[3,2,1]]);
  test([[1,2,3],[0,1,4],[0,0,1]]);
  test([[1,1,1],[0,1,1],[0,0,1]]);
}
<|endoftext|>


<commit_before>module.exports = function (config) {
    if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) {
        console.log('Make sure the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables are set.');
        process.exit(1);
    }

    // Check out https://saucelabs.com/platforms for all browser/platform combos
    var customLaunchers = {
        slIOS8: {
            base: 'SauceLabs',
            browserName: 'iPhone',
            platform: 'OS X 10.10',
            version: '8.4'
        },
        slIOS9: {
            base: 'SauceLabs',
            browserName: 'iPhone',
            platform: 'OS X 10.11',
            version: '9.1'
        },
        slAndroid4: {
            base: 'SauceLabs',
            browserName: 'Android',
            platform: 'Linux',
            version: '4.4'
        },
        slAndroid5: {
            base: 'SauceLabs',
            browserName: 'Android',
            platform: 'Linux',
            version: '5.1'
        },
        slChrome: {
            base: 'SauceLabs',
            browserName: 'chrome'
        },
        slChromeBeta: {
            base: 'SauceLabs',
            browserName: 'chrome',
            version: 'beta'
        },
        slChromeCanary: {
            base: 'SauceLabs',
            browserName: 'chrome',
            version: 'dev'
        },
        slFirefox42: {
            base: 'SauceLabs',
            browserName: 'firefox',
            platform: 'Windows 8.1',
            version: '42.0'
        },
        slFirefoxBeta: {
            base: 'SauceLabs',
            browserName: 'firefox',
            version: 'beta'
        },
        slFirefoxDev: {
            base: 'SauceLabs',
            browserName: 'firefox',
            version: 'dev'
        },
        slSafari8: {
            base: 'SauceLabs',
            browserName: 'safari',
            platform: 'OS X 10.10',
            version: '8'
        },
        slSafari9: {
            base: 'SauceLabs',
            browserName: 'safari',
            platform: 'OS X 10.11',
            version: '9'
        },
        slOpera: {
            base: 'SauceLabs',
            browserName: 'opera'
        },
        slEdge20: {
            base: 'SauceLabs',
            browserName: 'microsoftedge',
            platform: 'Windows 10',
            version: '20.10240'
        },
        slIE11: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows 8.1',
            version: '11'
        },
        slIE10: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows 8',
            version: '10'
        },
        slIE9: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows 7',
            version: '9'
        },
        slIE8: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows XP',
            version: '8'
        },
        slIE7: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows XP',
            version: '7'
        }
    };

    config.set({
        basePath: '',
        frameworks: ['jasmine'],
        files: [
            'polyfills.js',
            'node_modules/stackframe/dist/stackframe.js',
            'error-stack-parser.js',
            'spec/fixtures/captured-errors.js',
            'spec/spec-helper.js',
            'spec/*-spec.js'
        ],
        exclude: [],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        browserDisconnectTimeout : 10000,
        browserDisconnectTolerance : 1,
        browserNoActivityTimeout : 240000,
        captureTimeout : 240000,
        sauceLabs: {
            testName: 'error-stack-parser unit tests',
            recordScreenshots: false,
            connectOptions: {
                port: 5757,
                logfile: 'sauce_connect.log'
            }
        },
        customLaunchers: customLaunchers,
        browsers: Object.keys(customLaunchers),
        reporters: ['progress', 'saucelabs', 'coverage'],
        preprocessors: {
            'error-stack-parser.js': 'coverage'
        },
        coverageReporter: {
            type: 'lcov',
            dir: 'coverage'
        },
        singleRun: true
    });
};
<commit_msg>Remove Firefox beta from Sauce testing because it keeps failing due to unavailablity.<commit_after>module.exports = function (config) {
    if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) {
        console.log('Make sure the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables are set.');
        process.exit(1);
    }

    // Check out https://saucelabs.com/platforms for all browser/platform combos
    var customLaunchers = {
        slIOS8: {
            base: 'SauceLabs',
            browserName: 'iPhone',
            platform: 'OS X 10.10',
            version: '8.4'
        },
        slIOS9: {
            base: 'SauceLabs',
            browserName: 'iPhone',
            platform: 'OS X 10.11',
            version: '9.1'
        },
        slAndroid4: {
            base: 'SauceLabs',
            browserName: 'Android',
            platform: 'Linux',
            version: '4.4'
        },
        slAndroid5: {
            base: 'SauceLabs',
            browserName: 'Android',
            platform: 'Linux',
            version: '5.1'
        },
        slChrome: {
            base: 'SauceLabs',
            browserName: 'chrome'
        },
        slChromeBeta: {
            base: 'SauceLabs',
            browserName: 'chrome',
            version: 'beta'
        },
        slChromeCanary: {
            base: 'SauceLabs',
            browserName: 'chrome',
            version: 'dev'
        },
        slFirefox42: {
            base: 'SauceLabs',
            browserName: 'firefox',
            platform: 'Windows 8.1',
            version: '42.0'
        },
        slFirefoxDev: {
            base: 'SauceLabs',
            browserName: 'firefox',
            version: 'dev'
        },
        slSafari8: {
            base: 'SauceLabs',
            browserName: 'safari',
            platform: 'OS X 10.10',
            version: '8'
        },
        slSafari9: {
            base: 'SauceLabs',
            browserName: 'safari',
            platform: 'OS X 10.11',
            version: '9'
        },
        slOpera: {
            base: 'SauceLabs',
            browserName: 'opera'
        },
        slEdge20: {
            base: 'SauceLabs',
            browserName: 'microsoftedge',
            platform: 'Windows 10',
            version: '20.10240'
        },
        slIE11: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows 8.1',
            version: '11'
        },
        slIE10: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows 8',
            version: '10'
        },
        slIE9: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows 7',
            version: '9'
        },
        slIE8: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows XP',
            version: '8'
        },
        slIE7: {
            base: 'SauceLabs',
            browserName: 'internet explorer',
            platform: 'Windows XP',
            version: '7'
        }
    };

    config.set({
        basePath: '',
        frameworks: ['jasmine'],
        files: [
            'polyfills.js',
            'node_modules/stackframe/dist/stackframe.js',
            'error-stack-parser.js',
            'spec/fixtures/captured-errors.js',
            'spec/spec-helper.js',
            'spec/*-spec.js'
        ],
        exclude: [],
        port: 9876,
        colors: true,
        logLevel: config.LOG_INFO,
        autoWatch: true,
        browserDisconnectTimeout : 10000,
        browserDisconnectTolerance : 1,
        browserNoActivityTimeout : 240000,
        captureTimeout : 240000,
        sauceLabs: {
            testName: 'error-stack-parser unit tests',
            recordScreenshots: false,
            connectOptions: {
                port: 5757,
                logfile: 'sauce_connect.log'
            }
        },
        customLaunchers: customLaunchers,
        browsers: Object.keys(customLaunchers),
        reporters: ['progress', 'saucelabs', 'coverage'],
        preprocessors: {
            'error-stack-parser.js': 'coverage'
        },
        coverageReporter: {
            type: 'lcov',
            dir: 'coverage'
        },
        singleRun: true
    });
};
<|endoftext|>


<commit_before>YUI.add('aui-affix-tests', function(Y) {

    var Assert = Y.Assert,
        suite = new Y.Test.Suite('aui-affix'),
        affix,
        target = Y.one('#sidenav');

    function targetShouldHaveClassName(className) {
        Assert.isTrue(target.hasClass(className));
    }

    suite.add(new Y.Test.Case({
        name: 'Affix',

        setUp: function() {
            affix = new Y.Affix({
                target: target,
                offsetTop: 300,
                offsetBottom: 500
            });
        },

        tearDown: function() {
            affix.destructor();
            affix = null;
            target.removeClass(Y.Affix.CSS_CLASSES_BOTTOM);
            target.removeClass(Y.Affix.CSS_CLASSES_DEFAULT);
            target.removeClass(Y.Affix.CSS_CLASSES_TOP);
        },

        'should set attributes': function() {
            Assert.areEqual(affix.get('offsetBottom'), 500);
            Assert.areEqual(affix.get('offsetTop'), 300);
            Assert.areEqual(affix.get('target'), target);
        },

        'should be at the top of the doc': function() {
            window.scrollTo(0, 0);
            this.wait(function() {
                targetShouldHaveClassName(Y.Affix.CSS_CLASSES.TOP);
            }, 0);
        },

        'should not fire the positioning events when unnecessary': function() {
            var called = false;

            window.scrollTo(0, 0);
            affix.on(Y.Affix.EVENTS.TOP, function() {
                called = true;
            });

            window.scrollTo(0, 1);
            this.wait(function() {
                Assert.isFalse(called);
            }, 0);
        },

        'should be at the top of the doc and have no offsetTop': function() {
            affix.set('offsetTop', -Infinity);
            window.scrollTo(0, 0);
            this.wait(function() {
                targetShouldHaveClassName(Y.Affix.CSS_CLASSES.TOP);
            }, 0);
        },

        'should be at the end of the doc and have no offsetBottom': function() {
            affix.set('offsetBottom', -Infinity);
            window.scrollTo(0, Y.DOM.docHeight());
            this.wait(function() {
                targetShouldHaveClassName(Y.Affix.CSS_CLASSES.DEFAULT);
            }, 0);
        },

        'should be at the middle of the doc': function() {
            window.scrollTo(0, affix.get('offsetTop') + 1);
            this.wait(function() {
                targetShouldHaveClassName(Y.Affix.CSS_CLASSES.DEFAULT);
            }, 0);
        },

        'should be at the bottom of the doc': function() {
            window.scrollTo(0, Y.DOM.docHeight());
            this.wait(function() {
                targetShouldHaveClassName(Y.Affix.CSS_CLASSES.BOTTOM);
            }, 0);
        }
    }));

    Y.Test.Runner.add(suite);

}, '', {
    requires: ['test', 'aui-affix', 'node-screen']
});
<commit_msg>AUI-1150 Fix test for when there is no affix-top offset<commit_after>YUI.add('aui-affix-tests', function(Y) {

    var Assert = Y.Assert,
        suite = new Y.Test.Suite('aui-affix'),
        affix,
        target = Y.one('#sidenav');

    function targetShouldHaveClassName(className) {
        Assert.isTrue(target.hasClass(className));
    }

    suite.add(new Y.Test.Case({
        name: 'Affix',

        setUp: function() {
            affix = new Y.Affix({
                target: target,
                offsetTop: 300,
                offsetBottom: 500
            });
        },

        tearDown: function() {
            affix.destructor();
            affix = null;
            target.removeClass(Y.Affix.CSS_CLASSES_BOTTOM);
            target.removeClass(Y.Affix.CSS_CLASSES_DEFAULT);
            target.removeClass(Y.Affix.CSS_CLASSES_TOP);
        },

        'should set attributes': function() {
            Assert.areEqual(affix.get('offsetBottom'), 500);
            Assert.areEqual(affix.get('offsetTop'), 300);
            Assert.areEqual(affix.get('target'), target);
        },

        'should be at the top of the doc': function() {
            window.scrollTo(0, 0);
            this.wait(function() {
                targetShouldHaveClassName(Y.Affix.CSS_CLASSES.TOP);
            }, 0);
        },

        'should not fire the positioning events when unnecessary': function() {
            var called = false;

            window.scrollTo(0, 0);
            affix.on(Y.Affix.EVENTS.TOP, function() {
                called = true;
            });

            window.scrollTo(0, 1);
            this.wait(function() {
                Assert.isFalse(called);
            }, 0);
        },

        'should be at the top of the doc and have no offsetTop': function() {
            affix.set('offsetTop', -Infinity);
            window.scrollTo(0, 0);
            this.wait(function() {
                targetShouldHaveClassName(Y.Affix.CSS_CLASSES.DEFAULT);
            }, 0);
        },

        'should be at the end of the doc and have no offsetBottom': function() {
            affix.set('offsetBottom', -Infinity);
            window.scrollTo(0, Y.DOM.docHeight());
            this.wait(function() {
                targetShouldHaveClassName(Y.Affix.CSS_CLASSES.DEFAULT);
            }, 0);
        },

        'should be at the middle of the doc': function() {
            window.scrollTo(0, affix.get('offsetTop') + 1);
            this.wait(function() {
                targetShouldHaveClassName(Y.Affix.CSS_CLASSES.DEFAULT);
            }, 0);
        },

        'should be at the bottom of the doc': function() {
            window.scrollTo(0, Y.DOM.docHeight());
            this.wait(function() {
                targetShouldHaveClassName(Y.Affix.CSS_CLASSES.BOTTOM);
            }, 0);
        }
    }));

    Y.Test.Runner.add(suite);

}, '', {
    requires: ['test', 'aui-affix', 'node-screen']
});
<|endoftext|>


<commit_before>/* @flow weak */

import React from 'react'
import { Scene } from 'react-native-router-flux'

import Login from '../../units/urb-account-management/app/components/Login'
import Logout from '../../units/urb-account-management/app/components/Logout'
import ToDoScreen from '../../units/urb-example-todo/app/components/ToDoScreen'

export default function routes( MenuButton, viewerQuery, isAnonymous )
{
  return(
    <Scene key="main" tabs hideTabBar>
      <Scene key="/user/login" title="Login" component={ Login } leftButton={ MenuButton } initial={ isAnonymous } />
      <Scene key="/todo" leftButton={ MenuButton } initial={ ( ! isAnonymous ) }>
        <Scene title="To Do" component={ ToDoScreen } queries={ viewerQuery } />
      </Scene>
      <Scene key="/user/logout" title="Logout" component={ Logout } queries={ viewerQuery } leftButton={ MenuButton } />
    </Scene>
  )
}
<commit_msg>[app] Unable to run react native following instruction. Close #219<commit_after>/* @flow weak */

import React from 'react'
import { Scene } from 'react-native-router-flux'

import Login from '../../units/urb-account-management/app/components/Login'
import Logout from '../../units/urb-account-management/app/components/Logout'
import ToDoScreen from '../../units/urb-example-todo/app/components/ToDoScreen'

export default function routes( MenuButton, viewerQuery, isAnonymous )
{
  return(
    <Scene key='main' tabs hideTabBar>
      <Scene key='/user/login' title='Login' component={ Login } leftButton={ MenuButton } initial={ isAnonymous } />
      <Scene key='/todo' leftButton={ MenuButton } initial={ ( ! isAnonymous ) }>
        <Scene key='/todo-default' title='To Do' component={ ToDoScreen } queries={ viewerQuery } />
      </Scene>
      <Scene key='/user/logout' title='Logout' component={ Logout } queries={ viewerQuery } leftButton={ MenuButton } />
    </Scene>
  )
}
<|endoftext|>


<commit_before>'use strict';

var assertion_properties = [
  'Promise',
  'fulfilled',
  'fulfilledWith',
  'rejected',
  'rejectedWith',
  'finally',
  'eventually'
];

function isPromiseAssertionProperty(property) {
  var name = property && (property.name || property.value);
  return name && assertion_properties.indexOf(name) !== -1;
}

function ancestorReturns(parents) {
  for (var i = parents.length - 1; i >= 0; i--) {
    var parent = parents[i];
    var type = parent.type;
    if (type === 'ReturnStatement' || type === 'YieldExpression') {
      return true;
    }
    if (type === 'ArrowFunctionExpression' && parent.body.type === 'CallExpression') {
      return true;
    }
    if (type === 'FunctionExpression') {
      return false;
    }
  }
  return false;
}

module.exports = function(context) {
  return {
    MemberExpression: function(node) {
      if (!isPromiseAssertionProperty(node.property)) {
        return;
      }

      if (ancestorReturns(context.getAncestors(node))) {
        return;
      }

      context.report(node.property, 'Promise assertion must return or await.');
    }
  };
};
<commit_msg>fix: check for AwaitExpression<commit_after>'use strict';

var assertion_properties = [
  'Promise',
  'fulfilled',
  'fulfilledWith',
  'rejected',
  'rejectedWith',
  'finally',
  'eventually'
];

function isPromiseAssertionProperty(property) {
  var name = property && (property.name || property.value);
  return name && assertion_properties.indexOf(name) !== -1;
}

function ancestorReturns(parents) {
  for (var i = parents.length - 1; i >= 0; i--) {
    var parent = parents[i];
    var type = parent.type;
    if (type === 'ReturnStatement' || type === 'AwaitExpression' || type === 'YieldExpression') {
      return true;
    }
    if (type === 'ArrowFunctionExpression' && parent.body.type === 'CallExpression') {
      return true;
    }
    if (type === 'FunctionExpression') {
      return false;
    }
  }
  return false;
}

module.exports = function(context) {
  return {
    MemberExpression: function(node) {
      if (!isPromiseAssertionProperty(node.property)) {
        return;
      }

      if (ancestorReturns(context.getAncestors(node))) {
        return;
      }

      context.report(node.property, 'Promise assertion must return or await.');
    }
  };
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
  URLSlugs = require('mongoose-url-slugs'),
  Schema = mongoose.Schema;
/**
 * Pet Schema
 */
var PetSchema = new Schema({
	name: {
		type: String,
		default: '',
		required: 'Please fill Pet name',
		trim: true
	},
	created: {
		type: Date,
		default: Date.now
	},
	user: {
		type: Schema.ObjectId,
		ref: 'User'
	},
	type: {
		type: Schema.ObjectId,
		ref: 'Pettype'
	},
	description: {
		type: String,
		default: ''
	},
	isMissing: {
		type: Boolean
	},
	picture: {
		type: String,
		default: '',
		required: 'Please fill Pet picture'
	},
	color: {
		type: String,
		default: '',
		required: 'Please fill Pet color'
	},
	email: {
		type: String,
		default: '',
		required: 'Please fill Pet Email'
	},
	address: {
		type: String,
		default: '',
		required: 'Please fill Pet Address'
	},
	tel1: {
		type: String
	},
	tel2: {
		type: String
	},
	genre: {
		type: Schema.ObjectId,
		ref: 'Petgenre'
	},
	breed: {
		type: String,
		default: '',
		required: 'Please fill Pet breed',
		trim: true
	},
	yearOfBirth: {
		type: Date,
		default: Date.now
	},
	neutered: {
		type: Boolean
	},
	profileViews: {
		type: Number
	},
	isPrivate: {
		type: Boolean
	},
	isAdoption: {
		type: Boolean
	},
	registered: {
		type: Date,
		default: Date.now
	},
	slug: {
		type: String,
		required: 'Please fill slug name'
	}
});

PetSchema.plugin(new URLSlugs('name', {field: 'slug'}));

mongoose.model('Pet', PetSchema);

<commit_msg>db error in spanish<commit_after>'use strict';

/**
 * Module dependencies.
 */
var mongoose = require('mongoose'),
  URLSlugs = require('mongoose-url-slugs'),
  Schema = mongoose.Schema;
/**
 * Pet Schema
 */
var PetSchema = new Schema({
	name: {
		type: String,
		default: '',
		required: 'Please fill Pet name',
		trim: true
	},
	created: {
		type: Date,
		default: Date.now
	},
	user: {
		type: Schema.ObjectId,
		ref: 'User'
	},
	type: {
		type: Schema.ObjectId,
		ref: 'Pettype'
	},
	description: {
		type: String,
		default: ''
	},
	isMissing: {
		type: Boolean
	},
	picture: {
		type: String,
		default: '',
		required: 'Por favor, ingrese la foto de su mascota'
	},
	color: {
		type: String,
		default: '',
		required: 'Por favor, ingrese un color'
	},
	email: {
		type: String,
		default: '',
		required: 'Por favor, ingrese un email'
	},
	address: {
		type: String,
		default: '',
		required: 'Por favor, ingrese la dirección'
	},
	tel1: {
		type: String
	},
	tel2: {
		type: String
	},
	genre: {
		type: Schema.ObjectId,
		ref: 'Petgenre'
	},
	breed: {
		type: String,
		default: '',
		required: 'Por favor, ingrese la raza',
		trim: true
	},
	yearOfBirth: {
		type: Date,
		default: Date.now
	},
	neutered: {
		type: Boolean
	},
	profileViews: {
		type: Number
	},
	isPrivate: {
		type: Boolean
	},
	isAdoption: {
		type: Boolean
	},
	registered: {
		type: Date,
		default: Date.now
	},
	slug: {
		type: String,
		required: 'Please fill slug name'
	}
});

PetSchema.plugin(new URLSlugs('name', {field: 'slug'}));

mongoose.model('Pet', PetSchema);

<|endoftext|>


<commit_before>(function(window, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], function($) {
            return factory(window, $);
        });
    } else if (typeof module === 'object' && typeof module.exports === 'object') {
        module.exports = factory(window, require('jquery'));
    } else {
        window.lity = factory(window, window.jQuery || window.Zepto);
    }
}(typeof window !== "undefined" ? window : this, function(window, $) {
    'use strict';

    var document = window.document;

    var _win = $(window);
    var _html = $('html');
    var _instanceCount = 0;

    var _imageRegexp = /(^data:image\/)|(\.(png|jpe?g|gif|svg|webp|bmp|ico|tiff?)(\?\S*)?$)/i;
    var _youtubeRegex = /(youtube(-nocookie)?\.com|youtu\.be)\/(watch\?v=|v\/|u\/|embed\/?)?([\w-]{11})(.*)?/i;
    var _vimeoRegex =  /(vimeo(pro)?.com)\/(?:[^\d]+)?(\d+)\??(.*)?$/;
    var _googlemapsRegex = /((maps|www)\.)?google\.([^\/\?]+)\/?((maps\/?)?\?)(.*)/i;

    var _defaultHandlers = {
        image: imageHandler,
        inline: inlineHandler,
        iframe: iframeHandler
    };

    var focusableElementsSelector = 'a[href],area[href],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),button:not([disabled]),iframe,object,embed,[contenteditable],[tabindex]:not([tabindex^="-"])';

    var _defaultOptions = {
        handler: null,
        esc: true,
        template: '

Loading...

<button class="lity-close" type="button" title="Close (Press escape to close)" data-lity-close>×</button>

'
    };

    function globalToggle() {
        _html[_instanceCount > 0 ? 'addClass' : 'removeClass']('lity-active');
    }

    var transitionEndEvent = (function() {
        var el = document.createElement('div');

        var transEndEventNames = {
            WebkitTransition: 'webkitTransitionEnd',
            MozTransition: 'transitionend',
            OTransition: 'oTransitionEnd otransitionend',
            transition: 'transitionend'
        };

        for (var name in transEndEventNames) {
            if (el.style[name] !== undefined) {
                return transEndEventNames[name];
            }
        }

        return false;
    })();

    function transitionEnd(element) {
        var deferred = $.Deferred();

        if (!transitionEndEvent) {
            deferred.resolve();
        } else {
            element.one(transitionEndEvent, deferred.resolve);
            setTimeout(deferred.resolve, 500);
        }

        return deferred.promise();
    }

    function settings(currSettings, key, value) {
        if (arguments.length === 1) {
            return $.extend({}, currSettings);
        }

        if (typeof key === 'string') {
            if (typeof value === 'undefined') {
                return typeof currSettings[key] === 'undefined'
                    ? null
                    : currSettings[key];
            }

            currSettings[key] = value;
        } else {
            $.extend(currSettings, key);
        }

        return this;
    }

    function parseQueryParams(params){
        var pairs = decodeURI(params).split('&');
        var obj = {}, p;

        for (var i = 0, n = pairs.length; i < n; i++) {
            if (!pairs[i]) {
                continue;
            }

            p = pairs[i].split('=');
            obj[p[0]] = p[1];
        }

        return obj;
    }

    function appendQueryParams(url, params) {
        return url + (url.indexOf('?') > -1 ? '&' : '?') + $.param(params);
    }

    function error(msg) {
        return $('').append(msg);
    }

    function imageHandler(target) {
        if (!_imageRegexp.test(target)) {
            return false;
        }

        var img = $('');
        var deferred = $.Deferred();
        var failed = function() {
            deferred.reject(error('Failed loading image'));
        };

        img
            .on('load', function() {
                if (this.naturalWidth === 0) {
                    return failed();
                }

                deferred.resolve(img);
            })
            .on('error', failed)
        ;

        return deferred.promise();
    }

    function inlineHandler(target) {
        var el;

        try {
            el = $(target);
        } catch (e) {
            return false;
        }

        if (!el.length) {
            return false;
        }

        var placeholder = $('');

        return el
            .after(placeholder)
            .on('lity:ready', function(e, instance) {
                instance
                    .one('lity:remove', function() {
                        placeholder
                            .before(el.addClass('lity-hide'))
                            .remove()
                        ;
                    })
                ;
            })
        ;
    }

    function iframeHandler(target) {
        var matches, url = target;

        matches = _youtubeRegex.exec(target);

        if (matches) {
            url = appendQueryParams(
                'https://www.youtube' + (matches[2] || '') + '.com/embed/' + matches[4],
                $.extend(
                    {
                        autoplay: 1
                    },
                    parseQueryParams(matches[5] || '')
                )
            );
        }

        matches = _vimeoRegex.exec(target);

        if (matches) {
            url = appendQueryParams(
                'https://player.vimeo.com/video/' + matches[3],
                $.extend(
                    {
                        autoplay: 1
                    },
                    parseQueryParams(matches[4] || '')
                )
            );
        }

        matches = _googlemapsRegex.exec(target);

        if (matches) {
            url = appendQueryParams(
                'https://www.google.' + matches[3] + '/maps?' + matches[6],
                {
                    output: matches[6].indexOf('layer=c') > 0 ? 'svembed' : 'embed'
                }
            );
        }

        return '

';
    }

    function lity(options) {
        var _options = {},
            _handlers = {},
            _el,
            _instance,
            _content,
            _ready = $.Deferred().resolve();

        function keyup(e) {
            if (e.keyCode === 27) {
                close();
            }
        }

        function resize() {
            var height = document.documentElement.clientHeight
                ? document.documentElement.clientHeight
                : Math.round(_win.height());

            _content
                .css('max-height', Math.floor(height) + 'px')
                .trigger('lity:resize', [_instance])
            ;
        }

        function ready(el, content) {
            if (!_instance) {
                return;
            }

            _content = $(content);

            _win.on('resize', resize);
            resize();

            _instance
                .find('.lity-loader')
                .each(function() {
                    var el = $(this);

                    transitionEnd(el)
                        .always(function() {
                            el.remove();
                        })
                    ;
                })
            ;

            _instance
                .removeClass('lity-loading')
                .find('.lity-content')
                .empty()
                .append(_content)
            ;

            _content
                .removeClass('lity-hide')
                .find(focusableElementsSelector)
                .first()
                .focus()
            ;

            _content
                .trigger('lity:ready', [_instance, el])
            ;

            _ready.resolve();
        }

        function init(handler, content, options, el) {
            _ready = $.Deferred();

            _instanceCount++;
            globalToggle();

            _el = el;
            _instance = $(options.template)
                .addClass('lity-loading')
                .appendTo('body')
            ;

            _instance
                .find('[role="dialog"]')
                .attr('aria-hidden', 'false')
                .attr('tabindex', '-1')
                .focus()
            ;

            if (!!options.esc) {
                _win.on('keyup', keyup);
            }

            setTimeout(function() {
                _instance
                    .addClass('lity-opened lity-' + handler)
                    .on('click', '[data-lity-close]', function(e) {
                        if ($(e.target).is('[data-lity-close]')) {
                            close();
                        }
                    })
                    .trigger('lity:open', [_instance, el])
                ;

                $.when(content)
                    .always($.proxy(ready, null, el))
                ;
            }, 0);
        }

        function open(target, options, el) {
            var handler, content, handlers = $.extend({}, _defaultHandlers, _handlers);

            options = $.extend(
                {},
                _defaultOptions,
                _options,
                options
            );

            if (options.handler && handlers[options.handler]) {
                content = handlers[options.handler](target, popup);
                handler = options.handler;
            } else {
                var lateHandlers = {};

                // Run inline and iframe handlers after all other handlers
                $.each(['inline', 'iframe'], function(i, name) {
                    if (handlers[name]) {
                        lateHandlers[name] = handlers[name];
                    }

                    delete handlers[name];
                });

                var call = function(name, callback) {
                    // Handler might be "removed" by setting callback to null
                    if (!callback) {
                        return true;
                    }

                    content = callback(target, popup);

                    if (!!content) {
                        handler = name;
                        return false;
                    }
                };

                $.each(handlers, call);

                if (!handler) {
                    $.each(lateHandlers, call);
                }
            }

            if (content) {
                $.when(close())
                    .done($.proxy(init, null, handler, content, options, el))
                ;
            }

            return !!content;
        }

        function close() {
            if (!_instance) {
                return;
            }

            var deferred = $.Deferred();

            _ready.done(function() {
                _instanceCount--;
                globalToggle();

                _win
                    .off('resize', resize)
                    .off('keyup', keyup)
                ;

                if (_el) {
                    _el.focus();
                }

                _content.trigger('lity:close', [_instance]);

                _instance
                    .removeClass('lity-opened')
                    .addClass('lity-closed')
                ;

                var instance = _instance, content = _content;

                _el = null;
                _instance = null;
                _content = null;

                transitionEnd(content.add(instance))
                    .always(function() {
                        content.trigger('lity:remove', [instance]);
                        instance.remove();
                        deferred.resolve();
                    })
                ;
            });

            return deferred.promise();
        }

        function popup(event) {
            // If not an event, act as alias of popup.open
            if (!event.preventDefault) {
                return popup.open(event);
            }

            var el = $(this);
            var target = el.data('lity-target') || el.attr('href') || el.attr('src');

            if (!target) {
                return;
            }

            var options = el.data('lity-options') || el.data('lity');

            if (open(target, options, el)) {
                event.preventDefault();
            }
        }

        popup.handlers = $.proxy(settings, popup, _handlers);
        popup.options = $.proxy(settings, popup, _options);

        popup.open = function(target, options, el) {
            open(target, options, el);
            return popup;
        };

        popup.close = function() {
            close();
            return popup;
        };

        return popup.options(options);
    }

    lity.version = '@VERSION';
    lity.handlers = $.proxy(settings, lity, _defaultHandlers);
    lity.options = $.proxy(settings, lity, _defaultOptions);

    $(document).on('click', '[data-lity]', lity());

    return lity;
}));
<commit_msg>Use aria-label instead of title attribute for close button<commit_after>(function(window, factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], function($) {
            return factory(window, $);
        });
    } else if (typeof module === 'object' && typeof module.exports === 'object') {
        module.exports = factory(window, require('jquery'));
    } else {
        window.lity = factory(window, window.jQuery || window.Zepto);
    }
}(typeof window !== "undefined" ? window : this, function(window, $) {
    'use strict';

    var document = window.document;

    var _win = $(window);
    var _html = $('html');
    var _instanceCount = 0;

    var _imageRegexp = /(^data:image\/)|(\.(png|jpe?g|gif|svg|webp|bmp|ico|tiff?)(\?\S*)?$)/i;
    var _youtubeRegex = /(youtube(-nocookie)?\.com|youtu\.be)\/(watch\?v=|v\/|u\/|embed\/?)?([\w-]{11})(.*)?/i;
    var _vimeoRegex =  /(vimeo(pro)?.com)\/(?:[^\d]+)?(\d+)\??(.*)?$/;
    var _googlemapsRegex = /((maps|www)\.)?google\.([^\/\?]+)\/?((maps\/?)?\?)(.*)/i;

    var _defaultHandlers = {
        image: imageHandler,
        inline: inlineHandler,
        iframe: iframeHandler
    };

    var focusableElementsSelector = 'a[href],area[href],input:not([disabled]),select:not([disabled]),textarea:not([disabled]),button:not([disabled]),iframe,object,embed,[contenteditable],[tabindex]:not([tabindex^="-"])';

    var _defaultOptions = {
        handler: null,
        esc: true,
        template: '

Loading...

<button class="lity-close" type="button" aria-label="Close (Press escape to close)" data-lity-close>×</button>

'
    };

    function globalToggle() {
        _html[_instanceCount > 0 ? 'addClass' : 'removeClass']('lity-active');
    }

    var transitionEndEvent = (function() {
        var el = document.createElement('div');

        var transEndEventNames = {
            WebkitTransition: 'webkitTransitionEnd',
            MozTransition: 'transitionend',
            OTransition: 'oTransitionEnd otransitionend',
            transition: 'transitionend'
        };

        for (var name in transEndEventNames) {
            if (el.style[name] !== undefined) {
                return transEndEventNames[name];
            }
        }

        return false;
    })();

    function transitionEnd(element) {
        var deferred = $.Deferred();

        if (!transitionEndEvent) {
            deferred.resolve();
        } else {
            element.one(transitionEndEvent, deferred.resolve);
            setTimeout(deferred.resolve, 500);
        }

        return deferred.promise();
    }

    function settings(currSettings, key, value) {
        if (arguments.length === 1) {
            return $.extend({}, currSettings);
        }

        if (typeof key === 'string') {
            if (typeof value === 'undefined') {
                return typeof currSettings[key] === 'undefined'
                    ? null
                    : currSettings[key];
            }

            currSettings[key] = value;
        } else {
            $.extend(currSettings, key);
        }

        return this;
    }

    function parseQueryParams(params){
        var pairs = decodeURI(params).split('&');
        var obj = {}, p;

        for (var i = 0, n = pairs.length; i < n; i++) {
            if (!pairs[i]) {
                continue;
            }

            p = pairs[i].split('=');
            obj[p[0]] = p[1];
        }

        return obj;
    }

    function appendQueryParams(url, params) {
        return url + (url.indexOf('?') > -1 ? '&' : '?') + $.param(params);
    }

    function error(msg) {
        return $('').append(msg);
    }

    function imageHandler(target) {
        if (!_imageRegexp.test(target)) {
            return false;
        }

        var img = $('');
        var deferred = $.Deferred();
        var failed = function() {
            deferred.reject(error('Failed loading image'));
        };

        img
            .on('load', function() {
                if (this.naturalWidth === 0) {
                    return failed();
                }

                deferred.resolve(img);
            })
            .on('error', failed)
        ;

        return deferred.promise();
    }

    function inlineHandler(target) {
        var el;

        try {
            el = $(target);
        } catch (e) {
            return false;
        }

        if (!el.length) {
            return false;
        }

        var placeholder = $('');

        return el
            .after(placeholder)
            .on('lity:ready', function(e, instance) {
                instance
                    .one('lity:remove', function() {
                        placeholder
                            .before(el.addClass('lity-hide'))
                            .remove()
                        ;
                    })
                ;
            })
        ;
    }

    function iframeHandler(target) {
        var matches, url = target;

        matches = _youtubeRegex.exec(target);

        if (matches) {
            url = appendQueryParams(
                'https://www.youtube' + (matches[2] || '') + '.com/embed/' + matches[4],
                $.extend(
                    {
                        autoplay: 1
                    },
                    parseQueryParams(matches[5] || '')
                )
            );
        }

        matches = _vimeoRegex.exec(target);

        if (matches) {
            url = appendQueryParams(
                'https://player.vimeo.com/video/' + matches[3],
                $.extend(
                    {
                        autoplay: 1
                    },
                    parseQueryParams(matches[4] || '')
                )
            );
        }

        matches = _googlemapsRegex.exec(target);

        if (matches) {
            url = appendQueryParams(
                'https://www.google.' + matches[3] + '/maps?' + matches[6],
                {
                    output: matches[6].indexOf('layer=c') > 0 ? 'svembed' : 'embed'
                }
            );
        }

        return '

';
    }

    function lity(options) {
        var _options = {},
            _handlers = {},
            _el,
            _instance,
            _content,
            _ready = $.Deferred().resolve();

        function keyup(e) {
            if (e.keyCode === 27) {
                close();
            }
        }

        function resize() {
            var height = document.documentElement.clientHeight
                ? document.documentElement.clientHeight
                : Math.round(_win.height());

            _content
                .css('max-height', Math.floor(height) + 'px')
                .trigger('lity:resize', [_instance])
            ;
        }

        function ready(el, content) {
            if (!_instance) {
                return;
            }

            _content = $(content);

            _win.on('resize', resize);
            resize();

            _instance
                .find('.lity-loader')
                .each(function() {
                    var el = $(this);

                    transitionEnd(el)
                        .always(function() {
                            el.remove();
                        })
                    ;
                })
            ;

            _instance
                .removeClass('lity-loading')
                .find('.lity-content')
                .empty()
                .append(_content)
            ;

            _content
                .removeClass('lity-hide')
                .find(focusableElementsSelector)
                .first()
                .focus()
            ;

            _content
                .trigger('lity:ready', [_instance, el])
            ;

            _ready.resolve();
        }

        function init(handler, content, options, el) {
            _ready = $.Deferred();

            _instanceCount++;
            globalToggle();

            _el = el;
            _instance = $(options.template)
                .addClass('lity-loading')
                .appendTo('body')
            ;

            _instance
                .find('[role="dialog"]')
                .attr('aria-hidden', 'false')
                .attr('tabindex', '-1')
                .focus()
            ;

            if (!!options.esc) {
                _win.on('keyup', keyup);
            }

            setTimeout(function() {
                _instance
                    .addClass('lity-opened lity-' + handler)
                    .on('click', '[data-lity-close]', function(e) {
                        if ($(e.target).is('[data-lity-close]')) {
                            close();
                        }
                    })
                    .trigger('lity:open', [_instance, el])
                ;

                $.when(content)
                    .always($.proxy(ready, null, el))
                ;
            }, 0);
        }

        function open(target, options, el) {
            var handler, content, handlers = $.extend({}, _defaultHandlers, _handlers);

            options = $.extend(
                {},
                _defaultOptions,
                _options,
                options
            );

            if (options.handler && handlers[options.handler]) {
                content = handlers[options.handler](target, popup);
                handler = options.handler;
            } else {
                var lateHandlers = {};

                // Run inline and iframe handlers after all other handlers
                $.each(['inline', 'iframe'], function(i, name) {
                    if (handlers[name]) {
                        lateHandlers[name] = handlers[name];
                    }

                    delete handlers[name];
                });

                var call = function(name, callback) {
                    // Handler might be "removed" by setting callback to null
                    if (!callback) {
                        return true;
                    }

                    content = callback(target, popup);

                    if (!!content) {
                        handler = name;
                        return false;
                    }
                };

                $.each(handlers, call);

                if (!handler) {
                    $.each(lateHandlers, call);
                }
            }

            if (content) {
                $.when(close())
                    .done($.proxy(init, null, handler, content, options, el))
                ;
            }

            return !!content;
        }

        function close() {
            if (!_instance) {
                return;
            }

            var deferred = $.Deferred();

            _ready.done(function() {
                _instanceCount--;
                globalToggle();

                _win
                    .off('resize', resize)
                    .off('keyup', keyup)
                ;

                if (_el) {
                    _el.focus();
                }

                _content.trigger('lity:close', [_instance]);

                _instance
                    .removeClass('lity-opened')
                    .addClass('lity-closed')
                ;

                var instance = _instance, content = _content;

                _el = null;
                _instance = null;
                _content = null;

                transitionEnd(content.add(instance))
                    .always(function() {
                        content.trigger('lity:remove', [instance]);
                        instance.remove();
                        deferred.resolve();
                    })
                ;
            });

            return deferred.promise();
        }

        function popup(event) {
            // If not an event, act as alias of popup.open
            if (!event.preventDefault) {
                return popup.open(event);
            }

            var el = $(this);
            var target = el.data('lity-target') || el.attr('href') || el.attr('src');

            if (!target) {
                return;
            }

            var options = el.data('lity-options') || el.data('lity');

            if (open(target, options, el)) {
                event.preventDefault();
            }
        }

        popup.handlers = $.proxy(settings, popup, _handlers);
        popup.options = $.proxy(settings, popup, _options);

        popup.open = function(target, options, el) {
            open(target, options, el);
            return popup;
        };

        popup.close = function() {
            close();
            return popup;
        };

        return popup.options(options);
    }

    lity.version = '@VERSION';
    lity.handlers = $.proxy(settings, lity, _defaultHandlers);
    lity.options = $.proxy(settings, lity, _defaultOptions);

    $(document).on('click', '[data-lity]', lity());

    return lity;
}));
<|endoftext|>


<commit_before>var locomotive = require('locomotive');
var passport = require('passport');
var Controller = locomotive.Controller;

var AccountController = new Controller();

AccountController.show = function() {
  if (!this.req.isAuthenticated())
    return this.res.redirect(this.urlFor({ action: 'login' }));

  this.user = this.req.user;
  this.render();
};

AccountController.loginForm = function() {
  this.render();
};

AccountController.login = function() {
  var homePath = this.urlFor({ action: 'show' });
  var loginPath = this.urlFor({ action: 'login' });

  passport.authenticate('local', {
    successRedirect: homePath,
    failureRedirect: loginPath }
  )(this.__req, this.__res, this.__next);
};

AccountController.logout = function() {
  this.req.logout();
  this.res.redirect('/');
};

module.exports = AccountController;
<commit_msg>account_controller: Simplified login action<commit_after>var locomotive = require('locomotive');
var passport = require('passport');
var Controller = locomotive.Controller;

var AccountController = new Controller();

AccountController.show = function() {
  if (!this.req.isAuthenticated())
    return this.res.redirect(this.urlFor({ action: 'login' }));

  this.user = this.req.user;
  this.render();
};

AccountController.loginForm = function() {
  this.render();
};

AccountController.login = function() {
  passport.authenticate('local', {
    successRedirect: this.urlFor({ action: 'show' }),
    failureRedirect: this.urlFor({ action: 'login' }) }
  )(this.__req, this.__res, this.__next);
};

AccountController.logout = function() {
  this.req.logout();
  this.res.redirect('/');
};

module.exports = AccountController;
<|endoftext|>


<commit_before>import isEqual from 'lodash/isEqual';
import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

import { searchResources, toggleMap } from 'actions/searchActions';
import { changeSearchFilters } from 'actions/uiActions';
import { fetchUnits } from 'actions/unitActions';
import PageWrapper from 'pages/PageWrapper';
import DateHeader from 'shared/date-header';
import { injectT } from 'i18n';
import { scrollTo } from 'utils/domUtils';
import ResourceMap from 'shared/resource-map';
import SearchControls from './controls';
import searchPageSelector from './searchPageSelector';
import SearchResults from './results';

class UnconnectedSearchPage extends Component {
  constructor(props) {
    super(props);
    this.scrollToSearchResults = this.scrollToSearchResults.bind(this);
    this.searchResources = this.searchResources.bind(this);
  }

  componentDidMount() {
    const { actions, filters } = this.props;
    this.searchResources(filters);
    actions.fetchUnits();
  }

  componentWillUpdate(nextProps) {
    const { filters: currentFilters, actions } = this.props;
    const { filters: nextFilters } = nextProps;
    if (nextProps.isLoggedIn !== this.props.isLoggedIn) {
      this.searchResources(nextFilters);
      return;
    }
    if (isEqual(currentFilters, nextFilters)) {
      return;
    }
    actions.changeSearchFilters(nextFilters);
    this.searchResources(nextFilters);
  }

  scrollToSearchResults() {
    scrollTo(findDOMNode(this.refs.searchResults));
  }

  searchResources(filters) {
    const { actions, searchDone } = this.props;
    if (searchDone || filters.purpose || filters.people || filters.search) {
      actions.searchResources(filters);
    }
  }

  render() {
    const {
      actions,
      filters,
      isFetchingSearchResults,
      location,
      params,
      searchResultIds,
      searchDone,
      showMap,
      t,
    } = this.props;

    return (
      <PageWrapper className="search-page" title={t('SearchPage.title')}>
        <ResourceMap
          resourceIds={searchResultIds}
          showMap={showMap}
        />

{t('SearchPage.title')}

          <SearchControls
            location={location}
            params={params}
            scrollToSearchResults={this.scrollToSearchResults}
          />
          {searchDone && <DateHeader date={filters.date} />}
          {searchDone || isFetchingSearchResults ?
            <SearchResults
              isFetching={isFetchingSearchResults}
              onToggleMap={actions.toggleMap}
              ref="searchResults"
              searchResultIds={searchResultIds}
              showMap={showMap}
            />
            :
{t('SearchPage.helpText')}

          }

      </PageWrapper>
    );
  }
}

UnconnectedSearchPage.propTypes = {
  actions: PropTypes.object.isRequired,
  isFetchingSearchResults: PropTypes.bool.isRequired,
  filters: PropTypes.object.isRequired,
  isLoggedIn: PropTypes.bool.isRequired,
  location: PropTypes.object.isRequired,
  params: PropTypes.object.isRequired,
  searchDone: PropTypes.bool.isRequired,
  searchResultIds: PropTypes.array.isRequired,
  showMap: PropTypes.bool.isRequired,
  t: PropTypes.func.isRequired,
};

UnconnectedSearchPage = injectT(UnconnectedSearchPage); // eslint-disable-line

function mapDispatchToProps(dispatch) {
  const actionCreators = {
    changeSearchFilters,
    fetchUnits,
    searchResources,
    toggleMap,
  };

  return { actions: bindActionCreators(actionCreators, dispatch) };
}

export { UnconnectedSearchPage };
export default connect(searchPageSelector, mapDispatchToProps)(UnconnectedSearchPage);
<commit_msg>Remove search page title<commit_after>import isEqual from 'lodash/isEqual';
import React, { Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

import { searchResources, toggleMap } from 'actions/searchActions';
import { changeSearchFilters } from 'actions/uiActions';
import { fetchUnits } from 'actions/unitActions';
import PageWrapper from 'pages/PageWrapper';
import DateHeader from 'shared/date-header';
import { injectT } from 'i18n';
import { scrollTo } from 'utils/domUtils';
import ResourceMap from 'shared/resource-map';
import SearchControls from './controls';
import searchPageSelector from './searchPageSelector';
import SearchResults from './results';

class UnconnectedSearchPage extends Component {
  constructor(props) {
    super(props);
    this.scrollToSearchResults = this.scrollToSearchResults.bind(this);
    this.searchResources = this.searchResources.bind(this);
  }

  componentDidMount() {
    const { actions, filters } = this.props;
    this.searchResources(filters);
    actions.fetchUnits();
  }

  componentWillUpdate(nextProps) {
    const { filters: currentFilters, actions } = this.props;
    const { filters: nextFilters } = nextProps;
    if (nextProps.isLoggedIn !== this.props.isLoggedIn) {
      this.searchResources(nextFilters);
      return;
    }
    if (isEqual(currentFilters, nextFilters)) {
      return;
    }
    actions.changeSearchFilters(nextFilters);
    this.searchResources(nextFilters);
  }

  scrollToSearchResults() {
    scrollTo(findDOMNode(this.refs.searchResults));
  }

  searchResources(filters) {
    const { actions, searchDone } = this.props;
    if (searchDone || filters.purpose || filters.people || filters.search) {
      actions.searchResources(filters);
    }
  }

  render() {
    const {
      actions,
      filters,
      isFetchingSearchResults,
      location,
      params,
      searchResultIds,
      searchDone,
      showMap,
      t,
    } = this.props;

    return (
      <PageWrapper className="search-page" title={t('SearchPage.title')}>
        <ResourceMap
          resourceIds={searchResultIds}
          showMap={showMap}
        />

          <SearchControls
            location={location}
            params={params}
            scrollToSearchResults={this.scrollToSearchResults}
          />
          {searchDone && <DateHeader date={filters.date} />}
          {searchDone || isFetchingSearchResults ?
            <SearchResults
              isFetching={isFetchingSearchResults}
              onToggleMap={actions.toggleMap}
              ref="searchResults"
              searchResultIds={searchResultIds}
              showMap={showMap}
            />
            :
{t('SearchPage.helpText')}

          }

      </PageWrapper>
    );
  }
}

UnconnectedSearchPage.propTypes = {
  actions: PropTypes.object.isRequired,
  isFetchingSearchResults: PropTypes.bool.isRequired,
  filters: PropTypes.object.isRequired,
  isLoggedIn: PropTypes.bool.isRequired,
  location: PropTypes.object.isRequired,
  params: PropTypes.object.isRequired,
  searchDone: PropTypes.bool.isRequired,
  searchResultIds: PropTypes.array.isRequired,
  showMap: PropTypes.bool.isRequired,
  t: PropTypes.func.isRequired,
};

UnconnectedSearchPage = injectT(UnconnectedSearchPage); // eslint-disable-line

function mapDispatchToProps(dispatch) {
  const actionCreators = {
    changeSearchFilters,
    fetchUnits,
    searchResources,
    toggleMap,
  };

  return { actions: bindActionCreators(actionCreators, dispatch) };
}

export { UnconnectedSearchPage };
export default connect(searchPageSelector, mapDispatchToProps)(UnconnectedSearchPage);
<|endoftext|>


<commit_before>define(['jquery', 'backbone', 'underscore', 'leaflet', 'moxie.conf', 'moxie.position', 'places/views/DetailView', 'hbs!places/templates/base', 'hbs!places/templates/search', 'hbs!places/templates/results'],
    function($, Backbone, _, L, MoxieConf, userPosition, DetailView, baseTemplate, searchTemplate, resultsTemplate){

    var SearchView = Backbone.View.extend({

        // View constructor
        initialize: function() {
            _.bindAll(this);
            L.Icon.Default.imagePath = '/images/maps';
            this.collection.on("add remove reset", this.collectionUpdated, this);
            this.query = (this.options.params && this.options.params.q) ? this.options.params.q : '';
            this.user_position = null;
            this.latlngs = [];
            this.markers = [];
        },

        attributes: {
            'class': 'list-map'
        },

        // Event Handlers
        events: {
            'keypress :input': "searchEvent",
            'click .results-list > a': "clickResult"
        },

        clickResult: function(e) {
            e.preventDefault();
            // Find the POID from the click event
            var poid = $(e.target).data('poid');
            // We may have clicked on the actual LI element or a child... so search up parents
            // TODO: Find a better way of doing this...
            poid = (poid!==undefined) ? poid : $(e.target).parents('[data-poid]').data('poid');
            var poi = this.collection.get(poid);
            this.browseDetails(poi, _.bind(this.render_results, this, true));
        },

        browseDetails: function(poi, cb) {
            // Remove existing map markers
            _.each(this.markers, function(marker) {
                this.map.removeLayer(marker);
            }, this);
            // Create the detailView with the existing view element
            var detailView = new DetailView({el: this.el});
            detailView.map = this.map;
            detailView.user_position = this.user_position;
            detailView.poi = poi;
            detailView.renderPOI(cb);
            // Cleanup and navigate
            this.undelegateEvents();
            this.onClose();
            console.log(poi.id);
            Backbone.history.navigate('/places/'+poi.id, {replace:false});
        },

        update_map_markers: function(){
            // Remove the existing map markers
            _.each(this.markers, function(marker) {
                this.map.removeLayer(marker);
            }, this);
            // Create new list of markers from search results
            var markers = [];
            var latlngs = [];
            var map = this.map;
            this.$('.results-list a li').each(function(index) {
                var latlng = new L.LatLng($(this).data('lat'), $(this).data('lon'));
                var marker = new L.marker(latlng, {'title': $(this).find('h3').text()});
                marker.addTo(map);
                latlngs.push(latlng);
                markers.push(marker);
            });
            this.markers = markers;
            this.latlngs = latlngs;
            // Create map bounds based on our position and the results.
            var bounds = new L.LatLngBounds(latlngs);
            if (this.user_position) {
                bounds.extend(this.user_position);
            }
            bounds.pad(5);
            this.map.fitBounds(bounds);
        },

        searchEvent: function(ev) {
            if (ev.which === 13) {
                this.query = ev.target.value;
                this.search();
            }
        },

        updatePath: function() {
            var qstring = this.query ? "?"+$.param({'q': this.query}) : '';
            var path = MoxieConf.pathFor('places_search') + qstring;
            Backbone.history.navigate(path, {replace: false});
            return MoxieConf.endpoint + path;
        },

        search: function() {
            var headers;
            var url = this.updatePath();
            if (this.user_position) {
                headers = {'Geo-Position': this.user_position.join(';')};
            }
            $.ajax({
                url: url,
                dataType: 'json',
                headers: headers
            }).success(this.createPOIs);
        },

        createPOIs: function(data) {
            this.collection.reset(data._embedded.results);
        },

        collectionUpdated: function() {
            this.render_results(false);
        },

        render_results: function(back_button) {
            if (this.collection.length===1 && (back_button===undefined || !back_button)) {
                // We have only one result and the user hasn't navigated back
                // Set a curried callback bound with back_button=true:
                // This means if a user clicks back they get the results page with a single result
                this.browseDetails(this.collection.at(0), _.bind(this.render_results, this, true));
                return this;
            }
            // Events may not have been delegated (using 'back' button)
            this.delegateEvents(this.events);
            Backbone.trigger('domchange:title', "Search for Places of Interest");
            this.updatePath();
            $('#home').show();
            $('#back').hide();
            // Create the results-list div and search query input
            this.$('#list').html(searchTemplate({query: this.query}));
            // Actually populate the results-list
            var context = {results: this.collection.toArray(), query: this.query};
            this.$(".results-list").html(resultsTemplate(context));
            this.update_map_markers();
        },

        render: function() {
            this.$el.html(baseTemplate());
            this.map = L.map(this.$('#map')[0]).setView([MoxieConf.defaultLocation.coords.latitude, MoxieConf.defaultLocation.coords.longitude], 15, true);
            L.tileLayer('http://{s}.tile.cloudmade.com/b0a15b443b524d1a9739e92fe9dd8459/997/256/{z}/{x}/{y}.png', {
                maxZoom: 18,
                // Detect retina - if true 4* map tiles are downloaded
                detectRetina: true
            }).addTo(this.map);
            this.map.attributionControl.setPrefix('');
            userPosition.follow(this.handle_geolocation_query);
            return this;
        },

        invalidateMapSize: function() {
            this.map.invalidateSize();
            return this;
        },

        geo_error: function(error) {
            if (!this.user_position) {
                console.log("No user location");
            }
            this.search();
        },

        initial_call: true,
        user_marker: null,
        handle_geolocation_query: function(position) {
            this.user_position = [position.coords.latitude, position.coords.longitude];
            var you = new L.LatLng(position.coords.latitude, position.coords.longitude);
            if (this.user_marker) {
                this.map.removeLayer(this.user_marker);
            }
            this.user_marker = L.circle(you, 10, {color: 'red', fillColor: 'red', fillOpacity: 1.0});
            this.map.addLayer(this.user_marker);
            if (this.initial_call) {
                this.initial_call = false;
                this.search();
            }
        },

        onClose: function() {
            userPosition.unfollow(this.handle_geolocation_query);
        }
    });

    // Returns the View class
    return SearchView;
});
<commit_msg>Support for browsing categories in the searchView<commit_after>define(['jquery', 'backbone', 'underscore', 'leaflet', 'moxie.conf', 'moxie.position', 'places/views/DetailView', 'hbs!places/templates/base', 'hbs!places/templates/search', 'hbs!places/templates/results'],
    function($, Backbone, _, L, MoxieConf, userPosition, DetailView, baseTemplate, searchTemplate, resultsTemplate){

    var SearchView = Backbone.View.extend({

        // View constructor
        initialize: function() {
            _.bindAll(this);
            L.Icon.Default.imagePath = '/images/maps';
            this.collection.on("add remove reset", this.collectionUpdated, this);
            this.query = {};
            if (this.options.params && this.options.params.q) {
                this.query.q = this.options.params.q;
            }
            if (this.options.params && this.options.params.type) {
                this.query.type = this.options.params.type;
            }
            this.user_position = null;
            this.latlngs = [];
            this.markers = [];
        },

        attributes: {
            'class': 'list-map'
        },

        // Event Handlers
        events: {
            'keypress :input': "searchEvent",
            'click .results-list > a': "clickResult"
        },

        clickResult: function(e) {
            e.preventDefault();
            // Find the POID from the click event
            var poid = $(e.target).data('poid');
            // We may have clicked on the actual LI element or a child... so search up parents
            // TODO: Find a better way of doing this...
            poid = (poid!==undefined) ? poid : $(e.target).parents('[data-poid]').data('poid');
            var poi = this.collection.get(poid);
            this.browseDetails(poi, _.bind(this.render_results, this, true));
        },

        browseDetails: function(poi, cb) {
            // Remove existing map markers
            _.each(this.markers, function(marker) {
                this.map.removeLayer(marker);
            }, this);
            // Create the detailView with the existing view element
            var detailView = new DetailView({el: this.el});
            detailView.map = this.map;
            detailView.user_position = this.user_position;
            detailView.poi = poi;
            detailView.renderPOI(cb);
            // Cleanup and navigate
            this.undelegateEvents();
            this.onClose();
            console.log(poi.id);
            Backbone.history.navigate('/places/'+poi.id, {replace:false});
        },

        update_map_markers: function(){
            // Remove the existing map markers
            _.each(this.markers, function(marker) {
                this.map.removeLayer(marker);
            }, this);
            // Create new list of markers from search results
            var markers = [];
            var latlngs = [];
            var map = this.map;
            this.$('.results-list a li').each(function(index) {
                var latlng = new L.LatLng($(this).data('lat'), $(this).data('lon'));
                var marker = new L.marker(latlng, {'title': $(this).find('h3').text()});
                marker.addTo(map);
                latlngs.push(latlng);
                markers.push(marker);
            });
            this.markers = markers;
            this.latlngs = latlngs;
            // Create map bounds based on our position and the results.
            var bounds = new L.LatLngBounds(latlngs);
            if (this.user_position) {
                bounds.extend(this.user_position);
            }
            bounds.pad(5);
            this.map.fitBounds(bounds);
        },

        searchEvent: function(ev) {
            if (ev.which === 13) {
                this.query.q = ev.target.value;
                this.search();
            }
        },

        initial_path_update: true,
        updatePath: function() {
            var qstring = $.param(this.query);
            var path;
            if (qstring) {
                path = MoxieConf.pathFor('places_search') + '?' + qstring;
            } else {
                path = MoxieConf.pathFor('places_search');
            }
            Backbone.history.navigate(path, {trigger: false, replace: this.initial_path_update});
            this.initial_path_update = false;
            return MoxieConf.endpoint + path;
        },

        search: function() {
            var headers;
            var url = this.updatePath();
            if (this.user_position) {
                headers = {'Geo-Position': this.user_position.join(';')};
            }
            $.ajax({
                url: url,
                dataType: 'json',
                headers: headers
            }).success(this.createPOIs);
        },

        createPOIs: function(data) {
            this.collection.reset(data._embedded.results);
        },

        collectionUpdated: function() {
            this.render_results(false);
        },

        render_results: function(back_button) {
            if (this.collection.length===1 && (back_button===undefined || !back_button)) {
                // We have only one result and the user hasn't navigated back
                // Set a curried callback bound with back_button=true:
                // This means if a user clicks back they get the results page with a single result
                this.browseDetails(this.collection.at(0), _.bind(this.render_results, this, true));
                return this;
            }
            // Events may not have been delegated (using 'back' button)
            this.delegateEvents(this.events);
            Backbone.trigger('domchange:title', "Search for Places of Interest");
            this.updatePath();
            $('#home').show();
            $('#back').hide();
            // Create the results-list div and search query input
            this.$('#list').html(searchTemplate({query: this.query.q}));
            // Actually populate the results-list
            var context = {results: this.collection.toArray(), query: this.query.q};
            this.$(".results-list").html(resultsTemplate(context));
            this.update_map_markers();
        },

        render: function() {
            this.$el.html(baseTemplate());
            this.map = L.map(this.$('#map')[0]).setView([MoxieConf.defaultLocation.coords.latitude, MoxieConf.defaultLocation.coords.longitude], 15, true);
            L.tileLayer('http://{s}.tile.cloudmade.com/b0a15b443b524d1a9739e92fe9dd8459/997/256/{z}/{x}/{y}.png', {
                maxZoom: 18,
                // Detect retina - if true 4* map tiles are downloaded
                detectRetina: true
            }).addTo(this.map);
            this.map.attributionControl.setPrefix('');
            userPosition.follow(this.handle_geolocation_query);
            return this;
        },

        invalidateMapSize: function() {
            this.map.invalidateSize();
            return this;
        },

        geo_error: function(error) {
            if (!this.user_position) {
                console.log("No user location");
            }
            this.search();
        },

        initial_call: true,
        user_marker: null,
        handle_geolocation_query: function(position) {
            this.user_position = [position.coords.latitude, position.coords.longitude];
            var you = new L.LatLng(position.coords.latitude, position.coords.longitude);
            if (this.user_marker) {
                this.map.removeLayer(this.user_marker);
            }
            this.user_marker = L.circle(you, 10, {color: 'red', fillColor: 'red', fillOpacity: 1.0});
            this.map.addLayer(this.user_marker);
            if (this.initial_call) {
                this.initial_call = false;
                this.search();
            }
        },

        onClose: function() {
            userPosition.unfollow(this.handle_geolocation_query);
        }
    });

    // Returns the View class
    return SearchView;
});
<|endoftext|>