<commit_before>import { stringify, parse } from 'jsan';
import socketCluster from 'socketcluster-client';
import configureStore from './configureStore';
import { socketOptions } from './constants';

let instanceName;
let socket;
let channel;
let store = {};
let shouldInit = true;
let lastAction;
let filters;

function isFiltered(action) {
  if (!action || !action.action || !action.action.type) return false;
  return (
    filters.whitelist && !action.action.type.match(filters.whitelist.join('|')) ||
    filters.blacklist && action.action.type.match(filters.blacklist.join('|'))
  );
}

function relay(type, state, action, nextActionId) {
  if (filters && isFiltered(action)) return;
  setTimeout(() => {
    const message = {
      payload: state ? stringify(state) : '',
      action: action ? stringify(action) : '',
      nextActionId: nextActionId || '',
      type,
      id: socket.id,
      name: instanceName,
      init: shouldInit
    };
    if (shouldInit) shouldInit = false;
    socket.emit(socket.id ? 'log' : 'log-noid', message);
  }, 0);
}

function handleMessages(message) {
  if (message.type === 'DISPATCH') {
    store.liftedStore.dispatch(message.action);
  } else if (message.type === 'UPDATE') {
    relay('STATE', store.liftedStore.getState());
  } else if (message.type === 'SYNC') {
    if (socket.id && message.id !== socket.id) {
      store.liftedStore.dispatch({
        type: 'IMPORT_STATE', nextLiftedState: parse(message.state)
      });
    }
  }
}

function init(options) {
  if (channel) channel.unwatch();
  if (socket) socket.disconnect();
  if (options && options.port && !options.hostname) {
    options.hostname = 'localhost';
  }
  socket = socketCluster.connect(options && options.port ? options : socketOptions);

  socket.on('error', function (err) {
    console.warn(err);
  });

  socket.emit('login', 'master', (err, channelName) => {
    if (err) { console.warn(err); return; }
    channel = socket.subscribe(channelName);
    channel.watch(handleMessages);
    socket.on(channelName, handleMessages);
  });
  if (options && options.filters) {
    filters = options.filters;
  }
  if (options) instanceName = options.name;
  relay('STATE', store.liftedStore.getState());
}

function monitorReducer(state = {}, action) {
  lastAction = action.type;
  return state;
}

function filterStagedActions(state) {
  if (!filters) return state;

  const filteredStagedActionIds = [];
  const filteredComputedStates = [];

  state.stagedActionIds.forEach((id, idx) => {
    if (!isFiltered(state.actionsById[id])) {
      filteredStagedActionIds.push(id);
      filteredComputedStates.push(state.computedStates[idx]);
    }
  });

  return Object.assign({}, state, {
    stagedActionIds: filteredStagedActionIds,
    computedStates: filteredComputedStates
  });
}

function handleChange(state, liftedState) {
  const nextActionId = liftedState.nextActionId;
  const liftedAction = liftedState.actionsById[nextActionId - 1];
  const action = liftedAction.action;
  if (action.type === '@@INIT') {
    relay('INIT', state, { timestamp: Date.now() });
  } else if (lastAction !== 'TOGGLE_ACTION' && lastAction !== 'SWEEP') {
    if (lastAction === 'JUMP_TO_STATE') return;
    relay('ACTION', state, liftedAction, nextActionId);
  } else {
    relay('STATE', filterStagedActions(liftedState));
  }
}

export default function devTools(options) {
  return (next) => {
    return (reducer, initialState) => {
      store = configureStore(next, monitorReducer)(reducer, initialState);
      init(options);
      store.subscribe(() => { handleChange(store.getState(), store.liftedStore.getState()); });
      return store;
    };
  };
}
<commit_msg>Don't use `Object.assign` as it is not polyfilled<commit_after>import { stringify, parse } from 'jsan';
import socketCluster from 'socketcluster-client';
import configureStore from './configureStore';
import { socketOptions } from './constants';

let instanceName;
let socket;
let channel;
let store = {};
let shouldInit = true;
let lastAction;
let filters;

function isFiltered(action) {
  if (!action || !action.action || !action.action.type) return false;
  return (
    filters.whitelist && !action.action.type.match(filters.whitelist.join('|')) ||
    filters.blacklist && action.action.type.match(filters.blacklist.join('|'))
  );
}

function relay(type, state, action, nextActionId) {
  if (filters && isFiltered(action)) return;
  setTimeout(() => {
    const message = {
      payload: state ? stringify(state) : '',
      action: action ? stringify(action) : '',
      nextActionId: nextActionId || '',
      type,
      id: socket.id,
      name: instanceName,
      init: shouldInit
    };
    if (shouldInit) shouldInit = false;
    socket.emit(socket.id ? 'log' : 'log-noid', message);
  }, 0);
}

function handleMessages(message) {
  if (message.type === 'DISPATCH') {
    store.liftedStore.dispatch(message.action);
  } else if (message.type === 'UPDATE') {
    relay('STATE', store.liftedStore.getState());
  } else if (message.type === 'SYNC') {
    if (socket.id && message.id !== socket.id) {
      store.liftedStore.dispatch({
        type: 'IMPORT_STATE', nextLiftedState: parse(message.state)
      });
    }
  }
}

function init(options) {
  if (channel) channel.unwatch();
  if (socket) socket.disconnect();
  if (options && options.port && !options.hostname) {
    options.hostname = 'localhost';
  }
  socket = socketCluster.connect(options && options.port ? options : socketOptions);

  socket.on('error', function (err) {
    console.warn(err);
  });

  socket.emit('login', 'master', (err, channelName) => {
    if (err) { console.warn(err); return; }
    channel = socket.subscribe(channelName);
    channel.watch(handleMessages);
    socket.on(channelName, handleMessages);
  });
  if (options && options.filters) {
    filters = options.filters;
  }
  if (options) instanceName = options.name;
  relay('STATE', store.liftedStore.getState());
}

function monitorReducer(state = {}, action) {
  lastAction = action.type;
  return state;
}

function filterStagedActions(state) {
  if (!filters) return state;

  const filteredStagedActionIds = [];
  const filteredComputedStates = [];

  state.stagedActionIds.forEach((id, idx) => {
    if (!isFiltered(state.actionsById[id])) {
      filteredStagedActionIds.push(id);
      filteredComputedStates.push(state.computedStates[idx]);
    }
  });

  return { ...state,
    stagedActionIds: filteredStagedActionIds,
    computedStates: filteredComputedStates
  };
}

function handleChange(state, liftedState) {
  const nextActionId = liftedState.nextActionId;
  const liftedAction = liftedState.actionsById[nextActionId - 1];
  const action = liftedAction.action;
  if (action.type === '@@INIT') {
    relay('INIT', state, { timestamp: Date.now() });
  } else if (lastAction !== 'TOGGLE_ACTION' && lastAction !== 'SWEEP') {
    if (lastAction === 'JUMP_TO_STATE') return;
    relay('ACTION', state, liftedAction, nextActionId);
  } else {
    relay('STATE', filterStagedActions(liftedState));
  }
}

export default function devTools(options) {
  return (next) => {
    return (reducer, initialState) => {
      store = configureStore(next, monitorReducer)(reducer, initialState);
      init(options);
      store.subscribe(() => { handleChange(store.getState(), store.liftedStore.getState()); });
      return store;
    };
  };
}
<|endoftext|>


<commit_before>/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.XHRLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.XHRLoader.prototype = {

	constructor: THREE.XHRLoader,

	strict: true,

	load: function ( url, onLoad, onProgress, onError ) {

		if ( this.path !== undefined ) url = this.path + url;

		var scope = this;

		var cached = THREE.Cache.get( url );

		if ( cached !== undefined ) {

			if ( onLoad ) {

				setTimeout( function () {

					onLoad( cached );

				}, 0 );

			}

			return cached;

		}

		var request = new XMLHttpRequest();
		request.overrideMimeType( 'text/plain' );
		request.open( 'GET', url, true );

		request.addEventListener( 'load', function ( event ) {

			var response = event.target.response;

			THREE.Cache.add( url, response );

			if ( ( this.status === 200 && this.readyState === 4 ) && scope.strict ) {

				if ( onLoad ) onLoad( response );

				scope.manager.itemEnd( url );

			} else {

				if ( onError ) onError( event );

				scope.manager.itemError( url );

			}

		}, false );

		if ( onProgress !== undefined ) {

			request.addEventListener( 'progress', function ( event ) {

				onProgress( event );

			}, false );

		}

		request.addEventListener( 'error', function ( event ) {

			if ( onError ) onError( event );

			scope.manager.itemError( url );

		}, false );

		if ( this.responseType !== undefined ) request.responseType = this.responseType;
		if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;

		request.send( null );

		scope.manager.itemStart( url );

		return request;

	},

	setPath: function ( value ) {

		this.path = value;

	},

	setResponseType: function ( value ) {

		this.responseType = value;

	},

	setWithCredentials: function ( value ) {

		this.withCredentials = value;

	}

	setStrict: function ( value ) {

		this.strict = value;

	}

};
<commit_msg>Reverted adding of property, rewritten to accept http status 0.<commit_after>/**
 * @author mrdoob / http://mrdoob.com/
 */

THREE.XHRLoader = function ( manager ) {

	this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;

};

THREE.XHRLoader.prototype = {

	constructor: THREE.XHRLoader,

	load: function ( url, onLoad, onProgress, onError ) {

		if ( this.path !== undefined ) url = this.path + url;

		var scope = this;

		var cached = THREE.Cache.get( url );

		if ( cached !== undefined ) {

			if ( onLoad ) {

				setTimeout( function () {

					onLoad( cached );

				}, 0 );

			}

			return cached;

		}

		var request = new XMLHttpRequest();
		request.overrideMimeType( 'text/plain' );
		request.open( 'GET', url, true );

		request.addEventListener( 'load', function ( event ) {

			var response = event.target.response;

			THREE.Cache.add( url, response );

			if ( this.status === 200 ) {

				if ( onLoad ) onLoad( response );

				scope.manager.itemEnd( url );

			} else if ( this.status === 0 ) {

				// Some browsers return HTTP Status 0 when using non-http protocol
				// e.g. 'file://' or 'data://'. Handle as success.

				console.warn( 'THREE.XHRLoader: HTTP Status 0 received.' );

				if ( onLoad ) onLoad( response );

				scope.manager.itemEnd( url );

			} else {

				if ( onError ) onError( event );

				scope.manager.itemError( url );

			}

		}, false );

		if ( onProgress !== undefined ) {

			request.addEventListener( 'progress', function ( event ) {

				onProgress( event );

			}, false );

		}

		request.addEventListener( 'error', function ( event ) {

			if ( onError ) onError( event );

			scope.manager.itemError( url );

		}, false );

		if ( this.responseType !== undefined ) request.responseType = this.responseType;
		if ( this.withCredentials !== undefined ) request.withCredentials = this.withCredentials;

		request.send( null );

		scope.manager.itemStart( url );

		return request;

	},

	setPath: function ( value ) {

		this.path = value;

	},

	setResponseType: function ( value ) {

		this.responseType = value;

	},

	setWithCredentials: function ( value ) {

		this.withCredentials = value;

	}

};
<|endoftext|>


<commit_before>function getMonzo() {
  return {
    // general
    name: "Monzo Account",
    provider: "monzo",

    // auth
    authType: "oauth2",
    accessToken: null,
    accessExpires: -1,
    // variables below used while auth is being negotiated
    clientId: null,
    clientSecret: null,
    state: null,
    redirectUri: null,

    // other variables
    accountId: null,
    cardId: null
  };
}

// auth functions
function monzoAuth(monzo) {
  if (monzo.clientId == null) {
    throw new Error("clientId isn't set and yet auth was called!");
  }
  if (monzo.clientSecret == null) {
    throw new Error("clientSecret isn't set and yet auth was called!");
  }
  if (monzo.state == null) {
    throw new Error("state isn't set and yet auth was called!");
  }
  if (monzo.redirectUri == null) {
    throw new Error("redirectUri isn't set and yet auth was called!");
  }
  window.location = "https://auth.getmondo.co.uk/?client_id=" + monzo.clientId + "&redirect_uri=" + monzo.redirectUri + "&response_type=code&state=" + monzo.state;
}

function monzoCallback(monzo, authCode) {
  if (monzo.clientId == null) {
    throw new Error("clientId isn't set and yet callback was called!");
  }
  if (monzo.clientSecret == null) {
    throw new Error("clientSecret isn't set and yet callback was called!");
  }
  if (monzo.state == null) {
    throw new Error("state isn't set and yet callback was called!");
  }
  if (monzo.redirectUri == null) {
    throw new Error("redirectUri isn't set and yet callback was called!");
  }

  var request = new XMLHttpRequest();
  request.open("POST", "https://api.monzo.com/oauth2/token", false);
  request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  request.send("grant_type=authorization_code&client_id=" + monzo.clientId + "&client_secret=" + monzo.clientSecret + "&redirect_uri=" + monzo.redirectUri + "&code=" + authCode);
  if (request.status == 200) {
    monzo.accessToken = JSON.parse(request.responseText).access_token;
    monzo.accessExpires = Date.now() + JSON.parse(request.responseText).expires_in * 1000;
    // clear the variables we were using while getting an access token
    delete monzo["clientId"];
    delete monzo["clientSecret"];
    delete monzo["redirectUri"];
    delete monzo["state"];
    // get the account id
    var request = new XMLHttpRequest();
    request.open("GET", "https://api.monzo.com/accounts", false);
    request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
    request.send();
    monzo.accountId = JSON.parse(request.responseText).accounts[0].id;
    monzo.cardId = monzoGetCards(monzo).id;
  }
}

// HTML functions
function monzoTransactionHTML(monzo, id) {
  // alasql
  try {
    alasql("drop table transactions")
  } catch(err) {
    console.log(err.message);
  }
  alasql('CREATE TABLE transactions (' +
    'id STRING PRIMARY KEY,' +
    'created Date,' +
    'settled Date,' +
    'is_load BOOLEAN,' +
    'merchant_id STRING,' +
    'description STRING,' +
    'currency STRING,' +
    'amount DECIMAL(10,2),' +
    'account_balance DECIMAL(10,2),' +
    'notes STRING);');
  alasql('CREATE TABLE merchants (' +
    'id STRING PRIMARY KEY,' +
    'name STRING,' +
    'address STRING,' +
    'city STRING,' +
    'region STRING,' +
    'country STRING,' +
    'postcode STRING,' +
    'latitude DOUBLE PRECISION,' +
    'longitude DOUBLE PRECISION,' +
    'zoom_level INT,' +
    'created Date,' +
    'group_id STRING,' +
    'logo STRING,' +
    'emoji STRING,' +
    'category STRING);');

  transactions = monzoGetTransactions(monzo, true);
  for (var i = 0; i < transactions.length; i++) {
    var merchantId;
    if (transactions[i].merchant == null) {
      merchantId = null;
      if (transactions[i].is_load) {
        console.log("Found a transaction with no merchant, but it was a load...");
      } else {
        console.log("Found a transaction with no merchant - panic!")
      }
    } else {
      merchantId = transactions[i].merchant.id;
      if (alasql('SELECT id from merchants where id="' + merchantId + '"').length == 0) {
        // add merchant to alasql
        alasql('INSERT INTO merchants VALUES(' +
          '"' + transactions[i].merchant.id + '"' + ',' +
          '"' + transactions[i].merchant.name + '"' + ',' +
          '"' + transactions[i].merchant.address.address + '"' + ',' +
          '"' + transactions[i].merchant.address.city + '"' + ',' +
          '"' + transactions[i].merchant.address.region + '"' + ',' +
          '"' + transactions[i].merchant.address.country + '"' + ',' +
          '"' + transactions[i].merchant.address.postcode + '"' + ',' +
          transactions[i].merchant.address.latitude + ',' +
          transactions[i].merchant.address.longitude + ',' +
          transactions[i].merchant.address.zoom_level + ',' +
          '"' + transactions[i].merchant.created + '"' + ',' +
          '"' + transactions[i].merchant.group_id + '"' + ',' +
          '"' + transactions[i].merchant.logo + '"' + ',' +
          '"' + transactions[i].merchant.emoji + '"' + ',' +
          '"' + transactions[i].merchant.category + '");');
      }
    }
    alasql('INSERT INTO transactions VALUES(' +
      '"' + transactions[i].id + '"' + ',' +
      '"' + transactions[i].created + '"' + ',' +
      '"' + transactions[i].settled + '"' + ',' +
      transactions[i].is_load + ',' +
      '"' + merchantId + '"' + ',' +
      '"' + transactions[i].description + '"' + ',' +
      '"' + transactions[i].currency + '"' + ',' +
      transactions[i].amount / 100 + ',' +
      transactions[i].account_balance / 100 + ',' +
      '"' + transactions[i].notes + '"' + ');');
  }

  var HTML = "";
  HTML += "
" + monzo.name + "
";
  HTML += '

';
  return HTML;
}

function monzoDetailsHTML(monzo, id) {
  var HTML = "";
  var balance = monzoGetBalance(monzo);
  var card = monzoGetCards(monzo);
  HTML += "
Welcome, " + card.name + "!
";
  HTML += "
Balance: £" + (balance.balance*0.01).toFixed(2) + "
";
  HTML += "
You spent £" + (balance.spend_today*0.01).toFixed(2) + " today.
";
  if (card.status == "ACTIVE") {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") is currently active.
";
    HTML += 'Freeze your card
';
  } else if (card.status == "INACTIVE") {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") is currently frozen.
";
    HTML += 'Defrost your card
';
  } else {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") has unknown status!
";
  }
  return HTML;
}

// other functions
function monzoGetBalance(monzo) {
  var request = new XMLHttpRequest();
  request.open("GET", "https://api.monzo.com/balance?account_id=" + monzo.accountId, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText);
}

function monzoGetCards(monzo) {
  var request = new XMLHttpRequest();
  request.open("GET", "https://api.monzo.com/card/list?account_id=" + monzo.accountId, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText).cards[0];
}

function monzoGetTransactions(monzo, expand) {
  if (typeof expand === "undefined") { expand = false; }
  var request = new XMLHttpRequest();
  if (expand) {
    request.open("GET", "https://api.monzo.com/transactions?account_id=" + monzo.accountId + "&expand[]=merchant", false);
  } else {
    request.open("GET", "https://api.monzo.com/transactions?account_id=" + monzo.accountId, false);
  }
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText).transactions;
}

function monzoFreezeCard(monzo, targetStatus, id) {
  var request = new XMLHttpRequest();
  request.open("PUT", "https://api.monzo.com/card/toggle?card_id=" + monzo.cardId + "&status=" + targetStatus, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  document.getElementById("accountDetails").innerHTML = monzoDetailsHTML(monzo, id)
}<commit_msg>Added a fake merchant for top ups<commit_after>function getMonzo() {
  return {
    // general
    name: "Monzo Account",
    provider: "monzo",

    // auth
    authType: "oauth2",
    accessToken: null,
    accessExpires: -1,
    // variables below used while auth is being negotiated
    clientId: null,
    clientSecret: null,
    state: null,
    redirectUri: null,

    // other variables
    accountId: null,
    cardId: null
  };
}

// auth functions
function monzoAuth(monzo) {
  if (monzo.clientId == null) {
    throw new Error("clientId isn't set and yet auth was called!");
  }
  if (monzo.clientSecret == null) {
    throw new Error("clientSecret isn't set and yet auth was called!");
  }
  if (monzo.state == null) {
    throw new Error("state isn't set and yet auth was called!");
  }
  if (monzo.redirectUri == null) {
    throw new Error("redirectUri isn't set and yet auth was called!");
  }
  window.location = "https://auth.getmondo.co.uk/?client_id=" + monzo.clientId + "&redirect_uri=" + monzo.redirectUri + "&response_type=code&state=" + monzo.state;
}

function monzoCallback(monzo, authCode) {
  if (monzo.clientId == null) {
    throw new Error("clientId isn't set and yet callback was called!");
  }
  if (monzo.clientSecret == null) {
    throw new Error("clientSecret isn't set and yet callback was called!");
  }
  if (monzo.state == null) {
    throw new Error("state isn't set and yet callback was called!");
  }
  if (monzo.redirectUri == null) {
    throw new Error("redirectUri isn't set and yet callback was called!");
  }

  var request = new XMLHttpRequest();
  request.open("POST", "https://api.monzo.com/oauth2/token", false);
  request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  request.send("grant_type=authorization_code&client_id=" + monzo.clientId + "&client_secret=" + monzo.clientSecret + "&redirect_uri=" + monzo.redirectUri + "&code=" + authCode);
  if (request.status == 200) {
    monzo.accessToken = JSON.parse(request.responseText).access_token;
    monzo.accessExpires = Date.now() + JSON.parse(request.responseText).expires_in * 1000;
    // clear the variables we were using while getting an access token
    delete monzo["clientId"];
    delete monzo["clientSecret"];
    delete monzo["redirectUri"];
    delete monzo["state"];
    // get the account id
    var request = new XMLHttpRequest();
    request.open("GET", "https://api.monzo.com/accounts", false);
    request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
    request.send();
    monzo.accountId = JSON.parse(request.responseText).accounts[0].id;
    monzo.cardId = monzoGetCards(monzo).id;
  }
}

// HTML functions
function monzoTransactionHTML(monzo, id) {
  // alasql
  try {
    alasql("drop table transactions")
  } catch(err) {
    console.log(err.message);
  }
  alasql('CREATE TABLE transactions (' +
    'id STRING PRIMARY KEY,' +
    'created Date,' +
    'settled Date,' +
    'is_load BOOLEAN,' +
    'merchant_id STRING,' +
    'description STRING,' +
    'currency STRING,' +
    'amount DECIMAL(10,2),' +
    'account_balance DECIMAL(10,2),' +
    'notes STRING);');
  alasql('CREATE TABLE merchants (' +
    'id STRING PRIMARY KEY,' +
    'name STRING,' +
    'address STRING,' +
    'city STRING,' +
    'region STRING,' +
    'country STRING,' +
    'postcode STRING,' +
    'latitude DOUBLE PRECISION,' +
    'longitude DOUBLE PRECISION,' +
    'zoom_level INT,' +
    'created Date,' +
    'group_id STRING,' +
    'logo STRING,' +
    'emoji STRING,' +
    'category STRING);');
  // create a fake merchant for top-ups
  alasql('INSERT INTO merchants VALUES("merch_monzo", "Monzo", null, null, null, null, null, null, null, null, null, null, null, null;');

  transactions = monzoGetTransactions(monzo, true);
  for (var i = 0; i < transactions.length; i++) {
    var merchantId;
    if (transactions[i].merchant == null) {
      merchantId = null;
      if (transactions[i].is_load) {
        merchantId = "merch_monzo";
      }
    } else {
      merchantId = transactions[i].merchant.id;
      if (alasql('SELECT id from merchants where id="' + merchantId + '"').length == 0) {
        // add merchant to alasql
        alasql('INSERT INTO merchants VALUES(' +
          '"' + transactions[i].merchant.id + '"' + ',' +
          '"' + transactions[i].merchant.name + '"' + ',' +
          '"' + transactions[i].merchant.address.address + '"' + ',' +
          '"' + transactions[i].merchant.address.city + '"' + ',' +
          '"' + transactions[i].merchant.address.region + '"' + ',' +
          '"' + transactions[i].merchant.address.country + '"' + ',' +
          '"' + transactions[i].merchant.address.postcode + '"' + ',' +
          transactions[i].merchant.address.latitude + ',' +
          transactions[i].merchant.address.longitude + ',' +
          transactions[i].merchant.address.zoom_level + ',' +
          '"' + transactions[i].merchant.created + '"' + ',' +
          '"' + transactions[i].merchant.group_id + '"' + ',' +
          '"' + transactions[i].merchant.logo + '"' + ',' +
          '"' + transactions[i].merchant.emoji + '"' + ',' +
          '"' + transactions[i].merchant.category + '");');
      }
    }
    alasql('INSERT INTO transactions VALUES(' +
      '"' + transactions[i].id + '"' + ',' +
      '"' + transactions[i].created + '"' + ',' +
      '"' + transactions[i].settled + '"' + ',' +
      transactions[i].is_load + ',' +
      '"' + merchantId + '"' + ',' +
      '"' + transactions[i].description + '"' + ',' +
      '"' + transactions[i].currency + '"' + ',' +
      transactions[i].amount / 100 + ',' +
      transactions[i].account_balance / 100 + ',' +
      '"' + transactions[i].notes + '"' + ');');
  }

  var HTML = "";
  HTML += "
" + monzo.name + "
";
  HTML += '

';
  return HTML;
}

function monzoDetailsHTML(monzo, id) {
  var HTML = "";
  var balance = monzoGetBalance(monzo);
  var card = monzoGetCards(monzo);
  HTML += "
Welcome, " + card.name + "!
";
  HTML += "
Balance: £" + (balance.balance*0.01).toFixed(2) + "
";
  HTML += "
You spent £" + (balance.spend_today*0.01).toFixed(2) + " today.
";
  if (card.status == "ACTIVE") {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") is currently active.
";
    HTML += 'Freeze your card
';
  } else if (card.status == "INACTIVE") {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") is currently frozen.
";
    HTML += 'Defrost your card
';
  } else {
    HTML += "
Your card (last 4 digits " + card.last_digits + ") has unknown status!
";
  }
  return HTML;
}

// other functions
function monzoGetBalance(monzo) {
  var request = new XMLHttpRequest();
  request.open("GET", "https://api.monzo.com/balance?account_id=" + monzo.accountId, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText);
}

function monzoGetCards(monzo) {
  var request = new XMLHttpRequest();
  request.open("GET", "https://api.monzo.com/card/list?account_id=" + monzo.accountId, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText).cards[0];
}

function monzoGetTransactions(monzo, expand) {
  if (typeof expand === "undefined") { expand = false; }
  var request = new XMLHttpRequest();
  if (expand) {
    request.open("GET", "https://api.monzo.com/transactions?account_id=" + monzo.accountId + "&expand[]=merchant", false);
  } else {
    request.open("GET", "https://api.monzo.com/transactions?account_id=" + monzo.accountId, false);
  }
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  return JSON.parse(request.responseText).transactions;
}

function monzoFreezeCard(monzo, targetStatus, id) {
  var request = new XMLHttpRequest();
  request.open("PUT", "https://api.monzo.com/card/toggle?card_id=" + monzo.cardId + "&status=" + targetStatus, false);
  request.setRequestHeader("Authorization", "Bearer " + monzo.accessToken);
  request.send();
  document.getElementById("accountDetails").innerHTML = monzoDetailsHTML(monzo, id)
}<|endoftext|>


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

var docblockRe = /^\s*(\/\*\*(.|\n)*?\*\/)/;
var ltrimRe = /^\s*/;
/**
 * @param {String} contents
 * @return {String}
 */
function extract(contents) {
  var match = contents.match(docblockRe);
  if (match) {
    return match[0].replace(ltrimRe, '') || '';
  }
  return '';
}

var commentStartRe = /^\/\*\*?/;
var commentEndRe = /\*\/$/;
var wsRe = /[\t ]+/g;
var stringStartRe = /(\n|^) *\*/g;
var multilineRe = /(?:^|\n) *(@[^\n]*?) *\n *([^@\n\s][^@\n]+?) *\n/g;
var propertyRe = /(?:^|\n) *@(\S+) *([^\n]*)/g;

/**
 * @param {String} contents
 * @return {Array}
 */
function parse(docblock) {
  docblock = docblock
    .replace(commentStartRe, '')
    .replace(commentEndRe, '')
    .replace(wsRe, ' ')
    .replace(stringStartRe, '$1');

  // Normalize multi-line directives
  var prev = '';
  while (prev != docblock) {
    prev = docblock;
    docblock = docblock.replace(multilineRe, "\n$1 $2\n");
  }
  docblock = docblock.trim();

  var result = [];
  var match;
  while (match = propertyRe.exec(docblock)) {
    result.push([match[1], match[2]]);
  }

  return result;
}

/**
 * Same as parse but returns an object of prop: value instead of array of paris
 * If a property appers more than once the last one will be returned
 *
 * @param {String} contents
 * @return {Object}
 */
function parseAsObject(docblock) {
  var pairs = parse(docblock);
  var result = {};
  for (var i = 0; i < pairs.length; i++) {
    result[pairs[i][0]] = pairs[i][1];
  }
  return result;
}

exports.extract = extract;
exports.parse = parse;
exports.parseAsObject = parseAsObject;
<commit_msg>Fix docblock parsing to handle \r\n<commit_after>/**
 * Copyright 2013 Facebook, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var docblockRe = /^\s*(\/\*\*(.|\r?\n)*?\*\/)/;
var ltrimRe = /^\s*/;
/**
 * @param {String} contents
 * @return {String}
 */
function extract(contents) {
  var match = contents.match(docblockRe);
  if (match) {
    return match[0].replace(ltrimRe, '') || '';
  }
  return '';
}

var commentStartRe = /^\/\*\*?/;
var commentEndRe = /\*\/$/;
var wsRe = /[\t ]+/g;
var stringStartRe = /(\r?\n|^) *\*/g;
var multilineRe = /(?:^|\r?\n) *(@[^\r\n]*?) *\r?\n *([^@\r\n\s][^@\r\n]+?) *\r?\n/g;
var propertyRe = /(?:^|\r?\n) *@(\S+) *([^\r\n]*)/g;

/**
 * @param {String} contents
 * @return {Array}
 */
function parse(docblock) {
  docblock = docblock
    .replace(commentStartRe, '')
    .replace(commentEndRe, '')
    .replace(wsRe, ' ')
    .replace(stringStartRe, '$1');

  // Normalize multi-line directives
  var prev = '';
  while (prev != docblock) {
    prev = docblock;
    docblock = docblock.replace(multilineRe, "\n$1 $2\n");
  }
  docblock = docblock.trim();

  var result = [];
  var match;
  while (match = propertyRe.exec(docblock)) {
    result.push([match[1], match[2]]);
  }

  return result;
}

/**
 * Same as parse but returns an object of prop: value instead of array of paris
 * If a property appers more than once the last one will be returned
 *
 * @param {String} contents
 * @return {Object}
 */
function parseAsObject(docblock) {
  var pairs = parse(docblock);
  var result = {};
  for (var i = 0; i < pairs.length; i++) {
    result[pairs[i][0]] = pairs[i][1];
  }
  return result;
}

exports.extract = extract;
exports.parse = parse;
exports.parseAsObject = parseAsObject;
<|endoftext|>


<commit_before>angular
  .module("lift-ng", [])
  .service("plumbing", [ "$q", function($q){
    var defers = {};

    var create = function(id) {
      var q = $q.defer();
      defers[id] = q;
      return q;
    };

    var resolve = function(data, q) {
      if(data.msg) {
        q.reject(data.msg)
      } else {
        if (typeof data.data !== "undefined") {
          inject(data.data);
          q.resolve(data.data);
        }
        else {
          q.resolve();
        }
      }
      return q;
    };

    // Called by the LiftNgFutureActor when a Future is fulfilled
    var fulfill = function(data, id) {
      var theId = id || data.id;
      var q = defers[theId];
      if(typeof q !== "undefined" && q !== null) { // We found our awaiting defer/promise
        resolve(data, q);
        delete defers[theId];
      } else { // We arrived before the model which embeds us!
        resolve(data, create(theId));
      }
    };

    // Called to inject promises wherever our serializer encountered a Future
    var inject = function(model) {
      for(var k in model) {
        if(model[k] == null) {
          // Don't do anything, skip
        }
        // It is a future which we need to inject
        else if(model[k]["net.liftmodules.ng.Angular.future"]) {
          var id   = model[k]["net.liftmodules.ng.Angular.future"];
          var data = model[k].data;
          var msg  = model[k].msg;
          var q = defers[id];
          if(typeof q !== "undefined" && q !== null) { // The future resolved before we arrived here
            model[k] = q.promise;
            delete defers[id];
          } else if(data) { // The future had already RESOLVED at serialization time
            var d = $q.defer();
            d.resolve(data);
            model[k] = d.promise;
          } else if(msg) { // The future had already FAILED at serialization time
            var d = $q.defer();
            d.reject(msg);
            model[k] = d.promise;
          } else { // Promise/Future pending
            model[k] = create(id).promise;
          }
        }
        // Not a future, so check children
        else if(typeof model[k] === "object") {
          inject(model[k]);
        }
      }
    };

    return {
      createDefer: create,
      resolve: resolve,
      fulfill: fulfill,
      inject: inject
    }
  }])
  .service("liftProxy", ["$rootScope", "$q", "plumbing", function ($rootScope, $q, plumbing) {
    net_liftmodules_ng.init();

    var ajaxErrorCount = 0;

    var onErrorFor = function(req) { return function() { // Currying is so elegant in JS
      $rootScope.$emit("net_liftmodules_ng.ajaxError", ++ajaxErrorCount, req);
    }};

    var toData = function (requestData) {
      return requestData.name + "=" + encodeURIComponent(JSON.stringify({data: requestData.data}))
    };
    var toEnhancedReq = function (requestData) { return {
      data: toData(requestData),
      when: (new Date()).getTime(),
      onError: onErrorFor(requestData)
    }};

    var requestFor;
    if(net_liftmodules_ng.enhancedAjax) requestFor = toEnhancedReq;
    else requestFor = toData;

    var svc = {
      request: function (requestData) {
        var req = requestFor(requestData);
        var defer = $q.defer();

        var onSuccess = function(response) { $rootScope.$apply(function(){ // Must work under the watchful eye of angular
          // If there is no future ID, then we have our data and we're done.
          if(!response.futureId) {
            plumbing.resolve(response, defer);
          }

          // Otherwise, we need to plumb out a new promise because we'll get the value later.
          else {
            plumbing.createDefer(response.futureId).promise.then(
              function(data)  { defer.resolve(data)  },
              function(error) { defer.reject(error)  },
              function(notify){ defer.notify(notify) }
            )
          }

          if(ajaxErrorCount != 0)
            $rootScope.$emit("net_liftmodules_ng.ajaxErrorClear", req);
          ajaxErrorCount = 0;
        })};

        var onFailure = function() { $rootScope.$apply(function() {
          defer.reject("net.liftmodules.ng.Angular.ajaxErrorRetryExceeded");
        })};

        net_liftmodules_ng.ajax(req, onSuccess, onFailure, "json");

        return defer.promise;
      }
    };

    return svc;
  }
]);

var net_liftmodules_ng = net_liftmodules_ng || {};
// Careful to only init once, since it's possible to have multiple angular apps in one page
net_liftmodules_ng.isInitialized = false;
net_liftmodules_ng.init = function() { if(net_liftmodules_ng.enhancedAjax) { // Remove this condition once we can support Lift 3.x
  if(!net_liftmodules_ng.isInitialized) {
    // We've passed {data, when} to the ajax lift machinery, so we need to pull the data part back out.
    var onlyData = function(req) {
      // This check prevents us from screwing up any non-lift-ng ajax calls someone could possibly be making.
      if(typeof req === "object") return req.data;
      else return req;
    };

    var failureWrapper = function(req, onFailure) { return function() {
      if (typeof req === "object" && typeof req.onError === "function")
        req.onError();
      onFailure(); // We know lift always passes a failure cb function
    }};

    // Wrap the json call with our hooks in place
    var origCall = liftAjax.lift_actualJSONCall;
    liftAjax.lift_actualJSONCall = function(req, onSuccess, onFailure) {
      return origCall(onlyData(req), onSuccess, failureWrapper(req, onFailure));
    };

    // Override the sort function if we should retry ajax in order.
    if(net_liftmodules_ng.retryAjaxInOrder) {
      liftAjax.lift_ajaxQueueSort = function() {
        liftAjax.lift_ajaxQueue.sort(function (a, b) {
          // If both items are one of our doctored-up requests, grab our 'when' which is the original request time.
          if(typeof a.theData === "object" && a.theData.when && typeof b.theData === "object" && b.theData.when)
            return a.theData.when - b.theData.when;
          else // Not our stuff, so let's not screw around with the original order logic.
            return a.when - b.when;
        });
      };
    }

    net_liftmodules_ng.isInitialized = true;
  }
}};<commit_msg>Got the initial events for reporting comet errors<commit_after>angular
  .module("lift-ng", [])
  .service("plumbing", [ "$q", function($q){
    var defers = {};

    var create = function(id) {
      var q = $q.defer();
      defers[id] = q;
      return q;
    };

    var resolve = function(data, q) {
      if(data.msg) {
        q.reject(data.msg)
      } else {
        if (typeof data.data !== "undefined") {
          inject(data.data);
          q.resolve(data.data);
        }
        else {
          q.resolve();
        }
      }
      return q;
    };

    // Called by the LiftNgFutureActor when a Future is fulfilled
    var fulfill = function(data, id) {
      var theId = id || data.id;
      var q = defers[theId];
      if(typeof q !== "undefined" && q !== null) { // We found our awaiting defer/promise
        resolve(data, q);
        delete defers[theId];
      } else { // We arrived before the model which embeds us!
        resolve(data, create(theId));
      }
    };

    // Called to inject promises wherever our serializer encountered a Future
    var inject = function(model) {
      for(var k in model) {
        if(model[k] == null) {
          // Don't do anything, skip
        }
        // It is a future which we need to inject
        else if(model[k]["net.liftmodules.ng.Angular.future"]) {
          var id   = model[k]["net.liftmodules.ng.Angular.future"];
          var data = model[k].data;
          var msg  = model[k].msg;
          var q = defers[id];
          if(typeof q !== "undefined" && q !== null) { // The future resolved before we arrived here
            model[k] = q.promise;
            delete defers[id];
          } else if(data) { // The future had already RESOLVED at serialization time
            var d = $q.defer();
            d.resolve(data);
            model[k] = d.promise;
          } else if(msg) { // The future had already FAILED at serialization time
            var d = $q.defer();
            d.reject(msg);
            model[k] = d.promise;
          } else { // Promise/Future pending
            model[k] = create(id).promise;
          }
        }
        // Not a future, so check children
        else if(typeof model[k] === "object") {
          inject(model[k]);
        }
      }
    };

    return {
      createDefer: create,
      resolve: resolve,
      fulfill: fulfill,
      inject: inject
    }
  }])
  .service("liftProxy", ["$rootScope", "$q", "plumbing", function ($rootScope, $q, plumbing) {
    net_liftmodules_ng.init();

    var onCometError = function(errCount) {
      $rootScope.$apply(function(){
        $rootScope.$emit("net_liftmodules_ng.cometError", errCount);
      });
    };

    net_liftmodules_ng.onCometErrorCallbacks.push(onCometError);

    var ajaxErrorCount = 0;

    var onErrorFor = function(req) { return function() { // Currying is so elegant in JS
      $rootScope.$emit("net_liftmodules_ng.ajaxError", ++ajaxErrorCount, req);
    }};

    var toData = function (requestData) {
      return requestData.name + "=" + encodeURIComponent(JSON.stringify({data: requestData.data}))
    };
    var toEnhancedReq = function (requestData) { return {
      data: toData(requestData),
      when: (new Date()).getTime(),
      onError: onErrorFor(requestData)
    }};

    var requestFor;
    if(net_liftmodules_ng.enhancedAjax) requestFor = toEnhancedReq;
    else requestFor = toData;

    var svc = {
      request: function (requestData) {
        var req = requestFor(requestData);
        var defer = $q.defer();

        var onSuccess = function(response) { $rootScope.$apply(function(){ // Must work under the watchful eye of angular
          // If there is no future ID, then we have our data and we're done.
          if(!response.futureId) {
            plumbing.resolve(response, defer);
          }

          // Otherwise, we need to plumb out a new promise because we'll get the value later.
          else {
            plumbing.createDefer(response.futureId).promise.then(
              function(data)  { defer.resolve(data)  },
              function(error) { defer.reject(error)  },
              function(notify){ defer.notify(notify) }
            )
          }

          if(ajaxErrorCount != 0)
            $rootScope.$emit("net_liftmodules_ng.ajaxErrorClear", req);
          ajaxErrorCount = 0;
        })};

        var onFailure = function() { $rootScope.$apply(function() {
          defer.reject("net.liftmodules.ng.Angular.ajaxErrorRetryExceeded");
        })};

        net_liftmodules_ng.ajax(req, onSuccess, onFailure, "json");

        return defer.promise;
      }
    };

    return svc;
  }
]);

var net_liftmodules_ng = net_liftmodules_ng || {};
// Careful to only init once, since it's possible to have multiple angular apps in one page
net_liftmodules_ng.isInitialized = false;
// Using an array of callbacks to handle case of multiple angular apps
net_liftmodules_ng.onCometErrorCallbacks = [];
net_liftmodules_ng.init = function() { if(net_liftmodules_ng.enhancedAjax) { // Remove this condition once we can support Lift 3.x
  if(!net_liftmodules_ng.isInitialized) {
    // We've passed {data, when} to the ajax lift machinery, so we need to pull the data part back out.
    var onlyData = function(req) {
      // This check prevents us from screwing up any non-lift-ng ajax calls someone could possibly be making.
      if(typeof req === "object") return req.data;
      else return req;
    };

    var failureWrapper = function(req, onFailure) { return function() {
      if (typeof req === "object" && typeof req.onError === "function")
        req.onError();
      onFailure(); // We know lift always passes a failure cb function
    }};

    // Wrap the json call with our hooks in place
    var origAjax = liftAjax.lift_actualJSONCall;
    liftAjax.lift_actualJSONCall = function(req, onSuccess, onFailure) {
      return origAjax(onlyData(req), onSuccess, failureWrapper(req, onFailure));
    };

    // Override the sort function if we should retry ajax in order.
    if(net_liftmodules_ng.retryAjaxInOrder) {
      liftAjax.lift_ajaxQueueSort = function() {
        liftAjax.lift_ajaxQueue.sort(function (a, b) {
          // If both items are one of our doctored-up requests, grab our 'when' which is the original request time.
          if(typeof a.theData === "object" && a.theData.when && typeof b.theData === "object" && b.theData.when)
            return a.theData.when - b.theData.when;
          else // Not our stuff, so let's not screw around with the original order logic.
            return a.when - b.when;
        });
      };
    }

    var cometErrorCount = 0;
    var origCometOnFailure = liftComet.lift_handlerFailureFunc;
    liftComet.lift_handlerFailureFunc = function() {
      cometErrorCount++;
      for(var i = 0; i<net_liftmodules_ng.onCometErrorCallbacks.length; i++)
        net_liftmodules_ng.onCometErrorCallbacks[i](cometErrorCount);
      origCometOnFailure.apply(this, arguments);
    };

    net_liftmodules_ng.isInitialized = true;
  }
}};<|endoftext|>


<commit_before>/**
 * Slide menu plugin for App Framework UI
 * @copyright Intel
 *
 */;
(function($) {
    var startX, startY, blocking = false,
        checking = false,
        doMenu = true,
        showHide = false;
    $.ui.slideSideMenu = true;
    $.ui.fixedSideMenuWidth = 768;
    $.ui.ready(function() {
        //  $("head").append("<style>#afui #menu {display:block !important}</style>");
        if ($.os.ie) return; //ie has the menu at the bottom
        // return;
        var elems = $("#content, #header, #navbar");
        var $menu = $("#menu");
        var max = $("#menu").width();
        var menuState;
        var transTime = $.ui.transitionTime;

        window.addEventListener("resize", function(e) {
            max = $("#menu").width();
        });

        $("#afui").bind("touchstart", function(e) {
            startX = e.touches[0].pageX;
            startY = e.touches[0].pageY;

            checking = false;
            if (window.innerWidth >= $.ui.fixedSideMenuWidth)
                doMenu = false;
            else
                doMenu = true;
            max = $("#menu").width();
            menuState = $menu.css("display") == "block";
        });
        $("#afui").bind("touchmove", function(e) {

            if (!$.ui.slideSideMenu) return true;
            if (!checking) {
                checking = true;
                return true;
            }

            var dx = e.touches[0].pageX;
            var dy = e.touches[0].pageY;
            if (!menuState && dx < startX) return;
            else if (menuState && dx > startX) return;
            if (!doMenu || Math.abs(dy - startY) > Math.abs(dx - startX)) {
                doMenu = false;
                return true;
            }
            $menu.show();
            if (dx > max) return true;
            showHide = dx - startX > 0 ? 2 : false;
            var thePlace = Math.abs(dx - startX);

            if (!showHide) {
                thePlace = max - thePlace;
                transTime = (thePlace / max) * numOnly($.ui.transitionTime);
            } else {
                transTime = ((max - thePlace) / max) * numOnly($.ui.transitionTime);
            }

            elems.cssTranslate(thePlace + "px,0");
            e.preventDefault();
            e.stopPropagation();

        });
        $("#afui").bind("touchend", function(e) {

            if (doMenu && checking) {
                if (showHide) $menu.hide();
                $.ui.toggleSideMenu(showHide, null, transTime);
            }
            checking = false;
            doMenu = false;
        });
    });
})(af);<commit_msg>Fix for users doing extreme swiping on the screen.<commit_after>/**
 * Slide menu plugin for App Framework UI
 * @copyright Intel
 *
 */;
(function($) {
    var startX, startY, blocking = false,
        checking = false,
        doMenu = true,
        showHide = false;
    $.ui.slideSideMenu = true;
    $.ui.fixedSideMenuWidth = 768;
    var keepOpen=false;
    $.ui.ready(function() {
        //  $("head").append("<style>#afui #menu {display:block !important}</style>");
        if ($.os.ie) return; //ie has the menu at the bottom
        // return;
        var elems = $("#content, #header, #navbar");
        var $menu = $("#menu");
        var max = $("#menu").width();
        var menuState;
        var transTime = $.ui.transitionTime;

        window.addEventListener("resize", function(e) {
            max = $("#menu").width();
        });

        $("#afui").bind("touchstart", function(e) {
            startX = e.touches[0].pageX;
            startY = e.touches[0].pageY;

            checking = false;
            doMenu=false;
            keepOpen=false;
            if (window.innerWidth >= $.ui.fixedSideMenuWidth)
                doMenu = false,keepOpen=true;
            else
                doMenu = true;
            max = $("#menu").width();
            menuState = $menu.css("display") == "block";
        });
        $("#afui").bind("touchmove", function(e) {

            if (!$.ui.slideSideMenu||keepOpen) return true;
            if (!checking) {
                checking = true;
                doMenu=false;
                return true;
            }
            else
                doMenu=true;
             if(!doMenu) return;

            var dx = e.touches[0].pageX;
            var dy = e.touches[0].pageY;
            //if (!menuState && dx < startX) return;
            //else if (menuState && dx > startX) return;
            if (Math.abs(dy - startY) > Math.abs(dx - startX)) {
                doMenu = false;
                return true;
            }
            console.log(dx,max);
            if (dx > max) return true;
            console.log(dy,startY,dx,startX);
            showHide = dx - startX > 0 ? 2 : false;
            var thePlace = Math.abs(dx - startX);

            if (!showHide) {
                thePlace = max - thePlace;
                transTime = (thePlace / max) * numOnly($.ui.transitionTime);
            } else {
                transTime = ((max - thePlace) / max) * numOnly($.ui.transitionTime);
            }

            elems.cssTranslate(thePlace + "px,0");
            e.preventDefault();
            e.stopPropagation();

        });
        $("#afui").bind("touchend", function(e) {

            if (doMenu && checking&&!keepOpen) {
                $.ui.toggleSideMenu(showHide, null, transTime);
            }
            checking = false;
            doMenu = false;
            keepOpen=false;
        });
    });
})(af);<|endoftext|>


<commit_before>const btoa = require('btoa')
const groupBy = require('lodash.groupby')
const highwire = require('highwire')
const values = require('lodash.values')

const FailedStatusFoundError = require('./failed-status-found-error')
const PendingTimeoutError = require('./pending-timeout-error')

const GITHUB_TOKEN = process.env.GITHUB_TOKEN
const GITHUB_USER = process.env.GITHUB_USER
const GREENKEEPER_BOT_GITHUB_URL = 'https://github.com/greenkeeperio-bot'
const SQUASH_MERGES = process.env.SQUASH_MERGES || false
const DELETE_BRANCHES = process.env.DELETE_BRANCHES || true

const MINUTE = 1000 * 60
const HOUR = MINUTE * 60

const { get, put, post, del } = highwire

const headers = {
  'Authorization': `Basic ${btoa(GITHUB_USER + ':' + GITHUB_TOKEN)}`
}

const mergePR = (prUrl, prNumber, sha) => {
  const mergeData = {
    sha,
    commit_title: `greenkeeper-keeper(pr: ${prNumber}): :white_check_mark:`,
    commit_message: `greenkeeper-keeper(pr: ${prNumber}): :white_check_mark:`,
    squash: SQUASH_MERGES
  }

  put(`${prUrl}/merge`, mergeData, { headers })
}

const validatePR = (statusesUrl, timeout = MINUTE) =>
  get(statusesUrl, { headers })
    .then((response) => response.body)
    .then((statuses) => {
      const contexts = values(groupBy(statuses, 'context'))
      const latest = contexts.map((c) => c.sort((a, b) => a.id < b.id)[0])
      const failed = latest.filter((s) => s.state === 'failure')
      const pending = latest.filter((s) => s.state === 'pending')

      console.info('validating PR', {
        timeout,
        statusesUrl,
        latest: latest,
        failed: failed.length,
        pending: pending.length
      })

      if (failed.length) {
        console.log('found failed, rejecting...')
        return Promise.reject(new FailedStatusFoundError())
      }

      if (pending.length) {
        if (timeout > HOUR) {
          console.log('pending timeout exceeded, rejecting...')
          return Promise.reject(new PendingTimeoutError())
        }

        console.log('retrying statuses for:', statusesUrl)
        return new Promise((resolve) => setTimeout(() => resolve(), timeout))
          .then(() => validatePR(statusesUrl, timeout * 2))
      }

      console.log('statuses verified, continuing...')
      return Promise.resolve()
    })

const deleteBranch = (head) => {
  const { repo } = head
  const path = `/repos/${repo.full_name}/git/refs/heads/${head.ref}`
  const url = `https://api.github.com${path}`

  return del(url, { headers })
}

const openedByGreenKeeperBot = (sender) => {
  return sender.html_url === GREENKEEPER_BOT_GITHUB_URL
}

const buildErrorComment = (message, prNumber) => {
  return {
    body: `greenkeeper-keeper(pr: ${prNumber}): :x: \`${message}\``
  }
}

const commentWithError = (commentsUrl, prNumber, error) => {
  post(`${commentsUrl}`, buildErrorComment(error.message, prNumber), { headers })
}

module.exports.register = (server, options, next) => {
  server.route({
    method: 'POST',
    path: '/payload',
    handler (request, response) {
      response('ok')

      const { action, sender, pull_request, number } = request.payload

      if (action === 'opened' && openedByGreenKeeperBot(sender)) {
        request.log(['info', 'PR', 'validating'], pull_request.url)
        validatePR(pull_request.statuses_url)
          .then(() => request.log(['info', 'PR', 'validated']))
          .then(() => mergePR(
            pull_request.url,
            number,
            pull_request.head.sha
          ))
          .then(() => request.log(['info', 'PR', 'merged'], pull_request.url))
          .then(() => {
            if (DELETE_BRANCHES) {
              return deleteBranch(pull_request.head)
            }

            return Promise.resolve()
          })
          .catch((error) => {
            request.log(['error', 'PR'], error)
            commentWithError(pull_request.comments_url, number, error)
          })
      } else {
        request.log(['PR', 'skipping'])
      }
    }
  })

  next()
}

module.exports.register.attributes = {
  name: 'keeper',
  version: '0.0.1'
}
<commit_msg>checked for and rejected `error` state to fix #13<commit_after>const btoa = require('btoa')
const groupBy = require('lodash.groupby')
const highwire = require('highwire')
const values = require('lodash.values')

const FailedStatusFoundError = require('./failed-status-found-error')
const PendingTimeoutError = require('./pending-timeout-error')

const GITHUB_TOKEN = process.env.GITHUB_TOKEN
const GITHUB_USER = process.env.GITHUB_USER
const GREENKEEPER_BOT_GITHUB_URL = 'https://github.com/greenkeeperio-bot'
const SQUASH_MERGES = process.env.SQUASH_MERGES || false
const DELETE_BRANCHES = process.env.DELETE_BRANCHES || true

const MINUTE = 1000 * 60
const HOUR = MINUTE * 60

const { get, put, post, del } = highwire

const headers = {
  'Authorization': `Basic ${btoa(GITHUB_USER + ':' + GITHUB_TOKEN)}`
}

const mergePR = (prUrl, prNumber, sha) => {
  const mergeData = {
    sha,
    commit_title: `greenkeeper-keeper(pr: ${prNumber}): :white_check_mark:`,
    commit_message: `greenkeeper-keeper(pr: ${prNumber}): :white_check_mark:`,
    squash: SQUASH_MERGES
  }

  put(`${prUrl}/merge`, mergeData, { headers })
}

const validatePR = (statusesUrl, timeout = MINUTE) =>
  get(statusesUrl, { headers })
    .then((response) => response.body)
    .then((statuses) => {
      const contexts = values(groupBy(statuses, 'context'))
      const latest = contexts.map((c) => c.sort((a, b) => a.id < b.id)[0])
      const failed = latest.filter((s) => s.state === 'failure')
      const error = latest.filter((s) => s.state === 'error')
      const pending = latest.filter((s) => s.state === 'pending')

      console.info('validating PR', {
        timeout,
        statusesUrl,
        latest: latest,
        failed: failed.length,
        error: error.length,
        pending: pending.length
      })

      if (failed.length || error.length) {
        console.log('found failed, rejecting...')
        return Promise.reject(new FailedStatusFoundError())
      }

      if (pending.length) {
        if (timeout > HOUR) {
          console.log('pending timeout exceeded, rejecting...')
          return Promise.reject(new PendingTimeoutError())
        }

        console.log('retrying statuses for:', statusesUrl)
        return new Promise((resolve) => setTimeout(() => resolve(), timeout))
          .then(() => validatePR(statusesUrl, timeout * 2))
      }

      console.log('statuses verified, continuing...')
      return Promise.resolve()
    })

const deleteBranch = (head) => {
  const { repo } = head
  const path = `/repos/${repo.full_name}/git/refs/heads/${head.ref}`
  const url = `https://api.github.com${path}`

  return del(url, { headers })
}

const openedByGreenKeeperBot = (sender) => {
  return sender.html_url === GREENKEEPER_BOT_GITHUB_URL
}

const buildErrorComment = (message, prNumber) => {
  return {
    body: `greenkeeper-keeper(pr: ${prNumber}): :x: \`${message}\``
  }
}

const commentWithError = (commentsUrl, prNumber, error) => {
  post(`${commentsUrl}`, buildErrorComment(error.message, prNumber), { headers })
}

module.exports.register = (server, options, next) => {
  server.route({
    method: 'POST',
    path: '/payload',
    handler (request, response) {
      response('ok')

      const { action, sender, pull_request, number } = request.payload

      if (action === 'opened' && openedByGreenKeeperBot(sender)) {
        request.log(['info', 'PR', 'validating'], pull_request.url)
        validatePR(pull_request.statuses_url)
          .then(() => request.log(['info', 'PR', 'validated']))
          .then(() => mergePR(
            pull_request.url,
            number,
            pull_request.head.sha
          ))
          .then(() => request.log(['info', 'PR', 'merged'], pull_request.url))
          .then(() => {
            if (DELETE_BRANCHES) {
              return deleteBranch(pull_request.head)
            }

            return Promise.resolve()
          })
          .catch((error) => {
            request.log(['error', 'PR'], error)
            commentWithError(pull_request.comments_url, number, error)
          })
      } else {
        request.log(['PR', 'skipping'])
      }
    }
  })

  next()
}

module.exports.register.attributes = {
  name: 'keeper',
  version: '0.0.1'
}
<|endoftext|>


<commit_before>var hoverZoomPlugins = hoverZoomPlugins || [];
hoverZoomPlugins.push({
    name:'Le bon coin',
    version:'0.2',
    prepareImgLinks:function (callback) {
        var res = [];

        hoverZoom.urlReplace(res,
            'img[src*="thumbs"], span.thumbs',
            'thumbs',
            'images'
        );

        //sample url : https://img3.leboncoin.fr/ad-thumb/cc15170487f75709b751a61ee8b52b4ebed2a062.jpg
        //          -> https://img3.leboncoin.fr/ad-large/cc15170487f75709b751a61ee8b52b4ebed2a062.jpg
        hoverZoom.urlReplace(res,
            'img[src]',
            /\/ad-.*?\//,
            '/ad-large/'
        );

        callback($(res));
    }
});
<commit_msg>Fix for plug-in : LeBonCoin<commit_after>var hoverZoomPlugins = hoverZoomPlugins || [];
hoverZoomPlugins.push({
    name:'Le bon coin',
    version:'0.3',
    prepareImgLinks:function (callback) {
        var res = [];

        hoverZoom.urlReplace(res,
            'img[src*="thumbs"], span.thumbs',
            'thumbs',
            'images'
        );

        //sample url : https://img3.leboncoin.fr/ad-thumb/cc15170487f75709b751a61ee8b52b4ebed2a062.jpg
        //          -> https://img3.leboncoin.fr/ad-large/cc15170487f75709b751a61ee8b52b4ebed2a062.jpg
        hoverZoom.urlReplace(res,
            'img[src]',
            /\/ad-.*?\//,
            '/ad-large/'
        );

        //sample url : https://img.leboncoin.fr/api/v1/tenants/9a6387a1-6259-4f2c-a887-7e67f23dd4cb/domains/20bda58f-d650-462e-a72a-a5a7ecf2bf88/buckets/24265337-e7cc-489d-80fc-0c564d62a63b/images/c3/94/77/c39477a76bfe43ba5a164ffda5556324726f0c52.jpg?rule=ad-thumb
        //          -> https://img.leboncoin.fr/api/v1/tenants/9a6387a1-6259-4f2c-a887-7e67f23dd4cb/domains/20bda58f-d650-462e-a72a-a5a7ecf2bf88/buckets/24265337-e7cc-489d-80fc-0c564d62a63b/images/c3/94/77/c39477a76bfe43ba5a164ffda5556324726f0c52.jpg?rule=ad-large
        hoverZoom.urlReplace(res,
            'img[src]',
            /rule=ad-.*/,
            'rule=ad-large'
        );

        callback($(res), this.name);
    }
});
<|endoftext|>


<commit_before>/*
   Copyright (c) 2007-9, iUI Project Members
   See LICENSE.txt for licensing terms
 */

(function() {

var slideSpeed = 20;
var slideInterval = 0;

var currentPage = null;
var currentDialog = null;
var currentWidth = 0;
var currentHash = location.hash;
var hashPrefix = "#_";
var pageHistory = [];
var newPageCount = 0;
var checkTimer;
var hasOrientationEvent = false;
var portraitVal = "portrait";
var landscapeVal = "landscape";

// *************************************************************************************************

window.iui =
{
	animOn: false,	// Experimental slide animation with CSS transition disabled by default

	showPage: function(page, backwards)
	{
		if (page)
		{
			if (currentDialog)
			{
				currentDialog.removeAttribute("selected");
				currentDialog = null;
			}

			if (hasClass(page, "dialog"))
				showDialog(page);
			else
			{
				var fromPage = currentPage;
				currentPage = page;

				if (fromPage)
					setTimeout(slidePages, 0, fromPage, page, backwards);
				else
					updatePage(page, fromPage);
			}
		}
	},

	showPageById: function(pageId)
	{
		var page = $(pageId);
		if (page)
		{
			var index = pageHistory.indexOf(pageId);
			var backwards = index != -1;
			if (backwards)
				pageHistory.splice(index, pageHistory.length);

			iui.showPage(page, backwards);
		}
	},

	showPageByHref: function(href, args, method, replace, cb)
	{
		var req = new XMLHttpRequest();
		req.onerror = function()
		{
			if (cb)
				cb(false);
		};

		req.onreadystatechange = function()
		{
			if (req.readyState == 4)
			{
				if (replace)
					replaceElementWithSource(replace, req.responseText);
				else
				{
					var frag = document.createElement("div");
					frag.innerHTML = req.responseText;
					iui.insertPages(frag.childNodes);
				}
				if (cb)
					setTimeout(cb, 1000, true);
			}
		};

		method = method ? method.toUpperCase() : "GET";
		if (args && method == "GET")
		{
			href =  href + "?" + args.join("&");
		}
		req.open(method, href, true);
		var data = null;
		if (args && method != "GET")
		{
			req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			data = args.join("&");
		}
		req.send(data);
	},

	insertPages: function(nodes)
	{
		var targetPage;
		for (var i = 0; i < nodes.length; ++i)
		{
			var child = nodes[i];
			if (child.nodeType == 1)
			{
				if (!child.id)
					child.id = "__" + (++newPageCount) + "__";

				var clone = $(child.id);
				if (clone)
					clone.parentNode.replaceChild(child, clone);
				else
					document.body.appendChild(child);

				if (child.getAttribute("selected") == "true" || !targetPage)
					targetPage = child;

				--i;
			}
		}

		if (targetPage)
			iui.showPage(targetPage);
	},

	getSelectedPage: function()
	{
		for (var child = document.body.firstChild; child; child = child.nextSibling)
		{
			if (child.nodeType == 1 && child.getAttribute("selected") == "true")
				return child;
		}
	},
	isNativeUrl: function(href)
	{
		for(var i = 0; i < iui.nativeUrlPatterns.length; i++)
		{
			if(href.match(iui.nativeUrlPatterns[i])) return true;
		}
		return false;
	},
	nativeUrlPatterns: [
		new RegExp("^http:\/\/maps.google.com\/maps\?"),
		new RegExp("^mailto:"),
		new RegExp("^tel:"),
		new RegExp("^http:\/\/www.youtube.com\/watch\\?v="),
		new RegExp("^http:\/\/www.youtube.com\/v\/"),
		new RegExp("^javascript:"),

	]
};

// *************************************************************************************************

addEventListener("load", function(event)
{
	var page = iui.getSelectedPage();
	var locPage = getPageFromLoc();

	if (page)
			iui.showPage(page);

	if (locPage && (locPage != page))
		iui.showPage(locPage);

	setTimeout(preloadImages, 0);
	if (typeof window.onorientationchange == "object")
	{
		window.onorientationchange=orientChangeHandler;
		hasOrientationEvent = true;
		setTimeout(orientChangeHandler, 0);
	}
	setTimeout(checkOrientAndLocation, 0);
	checkTimer = setInterval(checkOrientAndLocation, 300);
}, false);

addEventListener("unload", function(event)
{
	return;
}, false);

addEventListener("click", function(event)
{
	var link = findParent(event.target, "a");
	if (link)
	{
		function unselect() { link.removeAttribute("selected"); }

		if (link.href && link.hash && link.hash != "#" && !link.target)
		{
			link.setAttribute("selected", "true");
			iui.showPage($(link.hash.substr(1)));
			setTimeout(unselect, 500);
		}
		else if (link == $("backButton"))
			history.back();
		else if (link.getAttribute("type") == "submit")
			submitForm(findParent(link, "form"));
		else if (link.getAttribute("type") == "cancel")
			cancelDialog(findParent(link, "form"));
		else if (link.target == "_replace")
		{
			link.setAttribute("selected", "progress");
			iui.showPageByHref(link.href, null, "GET", link, unselect);
		}
		else if (iui.isNativeUrl(link.href))
		{
			return;
		}
		else if (link.target == "_webapp")
		{
			location.href = link.href;
		}
		else if (!link.target)
		{
			link.setAttribute("selected", "progress");
			iui.showPageByHref(link.href, null, "GET", null, unselect);
		}
		else
			return;

		event.preventDefault();
	}
}, true);

addEventListener("click", function(event)
{
	var div = findParent(event.target, "div");
	if (div && hasClass(div, "toggle"))
	{
		div.setAttribute("toggled", div.getAttribute("toggled") != "true");
		event.preventDefault();
	}
}, true);

function getPageFromLoc()
{
	var page;
	var result = location.hash.match(/#_([^\?_]+)/);
	if (result)
		page = result[1];
	if (page)
		page = $(page);
	return page;
}

function orientChangeHandler()
{
	var orientation=window.orientation;
	switch(orientation)
	{
	case 0:
		setOrientation(portraitVal);
		break;

	case 90:
	case -90:
		setOrientation(landscapeVal);
		break;
	}
}

function checkOrientAndLocation()
{
	if (!hasOrientationEvent)
	{
	  if (window.innerWidth != currentWidth)
	  {
		  currentWidth = window.innerWidth;
		  var orient = currentWidth == 320 ? portraitVal : landscapeVal;
		  setOrientation(orient);
	  }
	}

	if (location.hash != currentHash)
	{
		var pageId = location.hash.substr(hashPrefix.length);
		iui.showPageById(pageId);
	}
}

function setOrientation(orient)
{
	document.body.setAttribute("orient", orient);
	setTimeout(scrollTo, 100, 0, 1);
}

function showDialog(page)
{
	currentDialog = page;
	page.setAttribute("selected", "true");

	if (hasClass(page, "dialog") && !page.target)
		showForm(page);
}

function showForm(form)
{
	form.onsubmit = function(event)
	{
		event.preventDefault();
		submitForm(form);
	};

	form.onclick = function(event)
	{
		if (event.target == form && hasClass(form, "dialog"))
			cancelDialog(form);
	};
}

function cancelDialog(form)
{
	form.removeAttribute("selected");
}

function updatePage(page, fromPage)
{
	if (!page.id)
		page.id = "__" + (++newPageCount) + "__";

	location.hash = currentHash = hashPrefix + page.id;
	pageHistory.push(page.id);

	var pageTitle = $("pageTitle");
	if (page.title)
		pageTitle.innerHTML = page.title;
	var ttlClass = page.getAttribute("ttlclass");
	pageTitle.className = ttlClass ? ttlClass : "";

	if (page.localName.toLowerCase() == "form" && !page.target)
		showForm(page);

	var backButton = $("backButton");
	if (backButton)
	{
		var prevPage = $(pageHistory[pageHistory.length-2]);
		if (prevPage && !page.getAttribute("hideBackButton"))
		{
			backButton.style.display = "inline";
			backButton.innerHTML = prevPage.title ? prevPage.title : "Back";
			var bbClass = prevPage.getAttribute("bbclass");
			backButton.className = (bbClass) ? 'button ' + bbClass : 'button';
		}
		else
			backButton.style.display = "none";
	}
}

function slidePages(fromPage, toPage, backwards)
{
	var axis = (backwards ? fromPage : toPage).getAttribute("axis");

	clearInterval(checkTimer);

	if (canDoSlideAnim() && axis != 'y')
	{
	  slide2(fromPage, toPage, backwards, slideDone);
	}
	else
	{
	  slide1(fromPage, toPage, backwards, axis, slideDone);
	}

	function slideDone()
	{
	  if (!hasClass(toPage, "dialog"))
		  fromPage.removeAttribute("selected");
	  checkTimer = setInterval(checkOrientAndLocation, 300);
	  setTimeout(updatePage, 0, toPage, fromPage);
	  fromPage.removeEventListener('webkitTransitionEnd', slideDone, false);
	}
}

function canDoSlideAnim()
{
  return (iui.animOn) && (typeof WebKitCSSMatrix == "object");
}

function slide1(fromPage, toPage, backwards, axis, cb)
{
	if (axis == "y")
		(backwards ? fromPage : toPage).style.top = "100%";
	else
		toPage.style.left = "100%";

	scrollTo(0, 1);
	toPage.setAttribute("selected", "true");
	var percent = 100;
	slide();
	var timer = setInterval(slide, slideInterval);

	function slide()
	{
		percent -= slideSpeed;
		if (percent <= 0)
		{
			percent = 0;
			clearInterval(timer);
			cb();
		}

		if (axis == "y")
		{
			backwards
				? fromPage.style.top = (100-percent) + "%"
				: toPage.style.top = percent + "%";
		}
		else
		{
			fromPage.style.left = (backwards ? (100-percent) : (percent-100)) + "%";
			toPage.style.left = (backwards ? -percent : percent) + "%";
		}
	}
}

function slide2(fromPage, toPage, backwards, cb)
{
	toPage.style.webkitTransitionDuration = '0ms'; // Turn off transitions to set toPage start offset
	// fromStart is always 0% and toEnd is always 0%
	// iPhone won't take % width on toPage
	var toStart = 'translateX(' + (backwards ? '-' : '') + window.innerWidth +	'px)';
	var fromEnd = 'translateX(' + (backwards ? '100%' : '-100%') + ')';
	toPage.style.webkitTransform = toStart;
	toPage.setAttribute("selected", "true");
	toPage.style.webkitTransitionDuration = '';	  // Turn transitions back on
	function startTrans()
	{
		fromPage.style.webkitTransform = fromEnd;
		toPage.style.webkitTransform = 'translateX(0%)'; //toEnd
	}
	fromPage.addEventListener('webkitTransitionEnd', cb, false);
	setTimeout(startTrans, 0);
}

function preloadImages()
{
	var preloader = document.createElement("div");
	preloader.id = "preloader";
	document.body.appendChild(preloader);
}

function submitForm(form)
{
	iui.showPageByHref(form.action, encodeForm(form), form.method || "GET");
}

function encodeForm(form)
{
	function encode(inputs)
	{
		for (var i = 0; i < inputs.length; ++i)
		{
			if (inputs[i].name)
				args.push(inputs[i].name + "=" + escape(inputs[i].value));
		}
	}

	var args = [];
	encode(form.getElementsByTagName("input"));
	encode(form.getElementsByTagName("textarea"));
	encode(form.getElementsByTagName("select"));
	return args;
}

function findParent(node, localName)
{
	while (node && (node.nodeType != 1 || node.localName.toLowerCase() != localName))
		node = node.parentNode;
	return node;
}

function hasClass(self, name)
{
	var re = new RegExp("(^|\\s)"+name+"($|\\s)");
	return re.exec(self.getAttribute("class")) != null;
}

function replaceElementWithSource(replace, source)
{
	var page = replace.parentNode;
	var parent = replace;
	while (page.parentNode != document.body)
	{
		page = page.parentNode;
		parent = parent.parentNode;
	}

	var frag = document.createElement(parent.localName);
	frag.innerHTML = source;

	page.removeChild(parent);

	while (frag.firstChild)
		page.appendChild(frag.firstChild);
}

function $(id) { return document.getElementById(id); }
function ddd() { console.log.apply(console, arguments); }

})();
<commit_msg>Enable CSS Transitions for slide by default with animOn = true<commit_after>/*
   Copyright (c) 2007-9, iUI Project Members
   See LICENSE.txt for licensing terms
 */

(function() {

var slideSpeed = 20;
var slideInterval = 0;

var currentPage = null;
var currentDialog = null;
var currentWidth = 0;
var currentHash = location.hash;
var hashPrefix = "#_";
var pageHistory = [];
var newPageCount = 0;
var checkTimer;
var hasOrientationEvent = false;
var portraitVal = "portrait";
var landscapeVal = "landscape";

// *************************************************************************************************

window.iui =
{
	animOn: true,	// Slide animation with CSS transition is now enabled by default where supported

	showPage: function(page, backwards)
	{
		if (page)
		{
			if (currentDialog)
			{
				currentDialog.removeAttribute("selected");
				currentDialog = null;
			}

			if (hasClass(page, "dialog"))
				showDialog(page);
			else
			{
				var fromPage = currentPage;
				currentPage = page;

				if (fromPage)
					setTimeout(slidePages, 0, fromPage, page, backwards);
				else
					updatePage(page, fromPage);
			}
		}
	},

	showPageById: function(pageId)
	{
		var page = $(pageId);
		if (page)
		{
			var index = pageHistory.indexOf(pageId);
			var backwards = index != -1;
			if (backwards)
				pageHistory.splice(index, pageHistory.length);

			iui.showPage(page, backwards);
		}
	},

	showPageByHref: function(href, args, method, replace, cb)
	{
		var req = new XMLHttpRequest();
		req.onerror = function()
		{
			if (cb)
				cb(false);
		};

		req.onreadystatechange = function()
		{
			if (req.readyState == 4)
			{
				if (replace)
					replaceElementWithSource(replace, req.responseText);
				else
				{
					var frag = document.createElement("div");
					frag.innerHTML = req.responseText;
					iui.insertPages(frag.childNodes);
				}
				if (cb)
					setTimeout(cb, 1000, true);
			}
		};

		method = method ? method.toUpperCase() : "GET";
		if (args && method == "GET")
		{
			href =  href + "?" + args.join("&");
		}
		req.open(method, href, true);
		var data = null;
		if (args && method != "GET")
		{
			req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			data = args.join("&");
		}
		req.send(data);
	},

	insertPages: function(nodes)
	{
		var targetPage;
		for (var i = 0; i < nodes.length; ++i)
		{
			var child = nodes[i];
			if (child.nodeType == 1)
			{
				if (!child.id)
					child.id = "__" + (++newPageCount) + "__";

				var clone = $(child.id);
				if (clone)
					clone.parentNode.replaceChild(child, clone);
				else
					document.body.appendChild(child);

				if (child.getAttribute("selected") == "true" || !targetPage)
					targetPage = child;

				--i;
			}
		}

		if (targetPage)
			iui.showPage(targetPage);
	},

	getSelectedPage: function()
	{
		for (var child = document.body.firstChild; child; child = child.nextSibling)
		{
			if (child.nodeType == 1 && child.getAttribute("selected") == "true")
				return child;
		}
	},
	isNativeUrl: function(href)
	{
		for(var i = 0; i < iui.nativeUrlPatterns.length; i++)
		{
			if(href.match(iui.nativeUrlPatterns[i])) return true;
		}
		return false;
	},
	nativeUrlPatterns: [
		new RegExp("^http:\/\/maps.google.com\/maps\?"),
		new RegExp("^mailto:"),
		new RegExp("^tel:"),
		new RegExp("^http:\/\/www.youtube.com\/watch\\?v="),
		new RegExp("^http:\/\/www.youtube.com\/v\/"),
		new RegExp("^javascript:"),

	]
};

// *************************************************************************************************

addEventListener("load", function(event)
{
	var page = iui.getSelectedPage();
	var locPage = getPageFromLoc();

	if (page)
			iui.showPage(page);

	if (locPage && (locPage != page))
		iui.showPage(locPage);

	setTimeout(preloadImages, 0);
	if (typeof window.onorientationchange == "object")
	{
		window.onorientationchange=orientChangeHandler;
		hasOrientationEvent = true;
		setTimeout(orientChangeHandler, 0);
	}
	setTimeout(checkOrientAndLocation, 0);
	checkTimer = setInterval(checkOrientAndLocation, 300);
}, false);

addEventListener("unload", function(event)
{
	return;
}, false);

addEventListener("click", function(event)
{
	var link = findParent(event.target, "a");
	if (link)
	{
		function unselect() { link.removeAttribute("selected"); }

		if (link.href && link.hash && link.hash != "#" && !link.target)
		{
			link.setAttribute("selected", "true");
			iui.showPage($(link.hash.substr(1)));
			setTimeout(unselect, 500);
		}
		else if (link == $("backButton"))
			history.back();
		else if (link.getAttribute("type") == "submit")
			submitForm(findParent(link, "form"));
		else if (link.getAttribute("type") == "cancel")
			cancelDialog(findParent(link, "form"));
		else if (link.target == "_replace")
		{
			link.setAttribute("selected", "progress");
			iui.showPageByHref(link.href, null, "GET", link, unselect);
		}
		else if (iui.isNativeUrl(link.href))
		{
			return;
		}
		else if (link.target == "_webapp")
		{
			location.href = link.href;
		}
		else if (!link.target)
		{
			link.setAttribute("selected", "progress");
			iui.showPageByHref(link.href, null, "GET", null, unselect);
		}
		else
			return;

		event.preventDefault();
	}
}, true);

addEventListener("click", function(event)
{
	var div = findParent(event.target, "div");
	if (div && hasClass(div, "toggle"))
	{
		div.setAttribute("toggled", div.getAttribute("toggled") != "true");
		event.preventDefault();
	}
}, true);

function getPageFromLoc()
{
	var page;
	var result = location.hash.match(/#_([^\?_]+)/);
	if (result)
		page = result[1];
	if (page)
		page = $(page);
	return page;
}

function orientChangeHandler()
{
	var orientation=window.orientation;
	switch(orientation)
	{
	case 0:
		setOrientation(portraitVal);
		break;

	case 90:
	case -90:
		setOrientation(landscapeVal);
		break;
	}
}

function checkOrientAndLocation()
{
	if (!hasOrientationEvent)
	{
	  if (window.innerWidth != currentWidth)
	  {
		  currentWidth = window.innerWidth;
		  var orient = currentWidth == 320 ? portraitVal : landscapeVal;
		  setOrientation(orient);
	  }
	}

	if (location.hash != currentHash)
	{
		var pageId = location.hash.substr(hashPrefix.length);
		iui.showPageById(pageId);
	}
}

function setOrientation(orient)
{
	document.body.setAttribute("orient", orient);
	setTimeout(scrollTo, 100, 0, 1);
}

function showDialog(page)
{
	currentDialog = page;
	page.setAttribute("selected", "true");

	if (hasClass(page, "dialog") && !page.target)
		showForm(page);
}

function showForm(form)
{
	form.onsubmit = function(event)
	{
		event.preventDefault();
		submitForm(form);
	};

	form.onclick = function(event)
	{
		if (event.target == form && hasClass(form, "dialog"))
			cancelDialog(form);
	};
}

function cancelDialog(form)
{
	form.removeAttribute("selected");
}

function updatePage(page, fromPage)
{
	if (!page.id)
		page.id = "__" + (++newPageCount) + "__";

	location.hash = currentHash = hashPrefix + page.id;
	pageHistory.push(page.id);

	var pageTitle = $("pageTitle");
	if (page.title)
		pageTitle.innerHTML = page.title;
	var ttlClass = page.getAttribute("ttlclass");
	pageTitle.className = ttlClass ? ttlClass : "";

	if (page.localName.toLowerCase() == "form" && !page.target)
		showForm(page);

	var backButton = $("backButton");
	if (backButton)
	{
		var prevPage = $(pageHistory[pageHistory.length-2]);
		if (prevPage && !page.getAttribute("hideBackButton"))
		{
			backButton.style.display = "inline";
			backButton.innerHTML = prevPage.title ? prevPage.title : "Back";
			var bbClass = prevPage.getAttribute("bbclass");
			backButton.className = (bbClass) ? 'button ' + bbClass : 'button';
		}
		else
			backButton.style.display = "none";
	}
}

function slidePages(fromPage, toPage, backwards)
{
	var axis = (backwards ? fromPage : toPage).getAttribute("axis");

	clearInterval(checkTimer);

	if (canDoSlideAnim() && axis != 'y')
	{
	  slide2(fromPage, toPage, backwards, slideDone);
	}
	else
	{
	  slide1(fromPage, toPage, backwards, axis, slideDone);
	}

	function slideDone()
	{
	  if (!hasClass(toPage, "dialog"))
		  fromPage.removeAttribute("selected");
	  checkTimer = setInterval(checkOrientAndLocation, 300);
	  setTimeout(updatePage, 0, toPage, fromPage);
	  fromPage.removeEventListener('webkitTransitionEnd', slideDone, false);
	}
}

function canDoSlideAnim()
{
  return (iui.animOn) && (typeof WebKitCSSMatrix == "object");
}

function slide1(fromPage, toPage, backwards, axis, cb)
{
	if (axis == "y")
		(backwards ? fromPage : toPage).style.top = "100%";
	else
		toPage.style.left = "100%";

	scrollTo(0, 1);
	toPage.setAttribute("selected", "true");
	var percent = 100;
	slide();
	var timer = setInterval(slide, slideInterval);

	function slide()
	{
		percent -= slideSpeed;
		if (percent <= 0)
		{
			percent = 0;
			clearInterval(timer);
			cb();
		}

		if (axis == "y")
		{
			backwards
				? fromPage.style.top = (100-percent) + "%"
				: toPage.style.top = percent + "%";
		}
		else
		{
			fromPage.style.left = (backwards ? (100-percent) : (percent-100)) + "%";
			toPage.style.left = (backwards ? -percent : percent) + "%";
		}
	}
}

function slide2(fromPage, toPage, backwards, cb)
{
	toPage.style.webkitTransitionDuration = '0ms'; // Turn off transitions to set toPage start offset
	// fromStart is always 0% and toEnd is always 0%
	// iPhone won't take % width on toPage
	var toStart = 'translateX(' + (backwards ? '-' : '') + window.innerWidth +	'px)';
	var fromEnd = 'translateX(' + (backwards ? '100%' : '-100%') + ')';
	toPage.style.webkitTransform = toStart;
	toPage.setAttribute("selected", "true");
	toPage.style.webkitTransitionDuration = '';	  // Turn transitions back on
	function startTrans()
	{
		fromPage.style.webkitTransform = fromEnd;
		toPage.style.webkitTransform = 'translateX(0%)'; //toEnd
	}
	fromPage.addEventListener('webkitTransitionEnd', cb, false);
	setTimeout(startTrans, 0);
}

function preloadImages()
{
	var preloader = document.createElement("div");
	preloader.id = "preloader";
	document.body.appendChild(preloader);
}

function submitForm(form)
{
	iui.showPageByHref(form.action, encodeForm(form), form.method || "GET");
}

function encodeForm(form)
{
	function encode(inputs)
	{
		for (var i = 0; i < inputs.length; ++i)
		{
			if (inputs[i].name)
				args.push(inputs[i].name + "=" + escape(inputs[i].value));
		}
	}

	var args = [];
	encode(form.getElementsByTagName("input"));
	encode(form.getElementsByTagName("textarea"));
	encode(form.getElementsByTagName("select"));
	return args;
}

function findParent(node, localName)
{
	while (node && (node.nodeType != 1 || node.localName.toLowerCase() != localName))
		node = node.parentNode;
	return node;
}

function hasClass(self, name)
{
	var re = new RegExp("(^|\\s)"+name+"($|\\s)");
	return re.exec(self.getAttribute("class")) != null;
}

function replaceElementWithSource(replace, source)
{
	var page = replace.parentNode;
	var parent = replace;
	while (page.parentNode != document.body)
	{
		page = page.parentNode;
		parent = parent.parentNode;
	}

	var frag = document.createElement(parent.localName);
	frag.innerHTML = source;

	page.removeChild(parent);

	while (frag.firstChild)
		page.appendChild(frag.firstChild);
}

function $(id) { return document.getElementById(id); }
function ddd() { console.log.apply(console, arguments); }

})();
<|endoftext|>


<commit_before>import {focus} from './actions';

const getFocusHandler = (store)=> ({target})=> {
  const focusElemKey = target.getAttribute('data-focus') || 'unmanaged';
  const currentElemKey = store.getState().focus.element;

  if (currentElemKey !== focusElemKey) {
    store.dispatch(focus(focusElemKey));
  }
};

export default (createStore)=> (reducer, state, enhancer)=> {
  const {documentElement} = document;

  const store = createStore(reducer, state, enhancer);

  documentElement.addEventListener('focus', getFocusHandler(store), true);

  let currentElemKey = null;

  store.subscribe(async ()=> {
    // delay execution to after browser events have been handled.
    await null;

    const focusElemKey = store.getState().focus.element;
    // TODO: Is this premeture optimization?
    // Could just run query selector, but that would happen each time the
    // store changes.
    if (currentElemKey !== focusElemKey) {

      if (focusElemKey === null) {
        document.activeElement.blur();
      } else {
        currentElemKey = focusElemKey;
        const elem = document.querySelector(`[data-focus="${focusElemKey}"]`);
        if (elem) {
          elem.focus();
        }
      }
    }
  });

  return store;
};
<commit_msg>resetting current element key for clear-focus<commit_after>import {focus} from './actions';

const getFocusHandler = (store)=> ({target})=> {
  const focusElemKey = target.getAttribute('data-focus') || 'unmanaged';
  const currentElemKey = store.getState().focus.element;

  if (currentElemKey !== focusElemKey) {
    store.dispatch(focus(focusElemKey));
  }
};

export default (createStore)=> (reducer, state, enhancer)=> {
  const {documentElement} = document;

  const store = createStore(reducer, state, enhancer);

  documentElement.addEventListener('focus', getFocusHandler(store), true);

  let currentElemKey = null;

  store.subscribe(async ()=> {
    // delay execution to after browser events have been handled.
    await null;

    const focusElemKey = store.getState().focus.element;
    // TODO: Is this premeture optimization?
    // Could just run query selector, but that would happen each time the
    // store changes.
    if (currentElemKey !== focusElemKey) {
      currentElemKey = focusElemKey;

      if (focusElemKey === null) {
        document.activeElement.blur();
      } else {
        const elem = document.querySelector(`[data-focus="${focusElemKey}"]`);
        if (elem) {
          elem.focus();
        }
      }
    }
  });

  return store;
};
<|endoftext|>