<commit_before>(function (document) {
  'use strict';

  var querySelector = document.querySelector.bind(document);

  var TURN_TIME = '10';
  var storyId, fbEntries, fbTurn, connection, uid, connected, timeOffset, turnStartTime; //turnObject;
  var fb = new Firebase('https://moword.firebaseio.com');
  var fbConnected = fb.child('.info/connected');
  var storyTextElement = querySelector('#storyText');
  var storyInputElement = querySelector('#storyInput');
  var loginWindow = querySelector('#login');
  var googleLogin = querySelector('#googleLogin');
  var authButton = querySelector('#authButton');
  var loggedIn = false;
  var timer = querySelector('#timer');
  var turnKeys = [];
  var turnInProgress = false;
  //var candidates = [];

  fb.child('.info').child('serverTimeOffset').once('value', function(snap) {
    timeOffset = snap.val();
  });

  fbConnected.on('value', function(snap) {
    connected = snap.val();
    setOnlineStatus();
  });

  function setOnlineStatus() {
    if (connected && uid) {
      // We're connected and the user is authorized
      // add this device to the users connections list
      connection = fb.child('people').child(uid).child('online').push(true);
      connection.onDisconnect().remove();
    } else if (connection) {
      connection.remove();
    }
  }

  fb.child('stories').limitToLast(10).once('value', function(snapshot) {
    var stories = snapshot.val();
    var storyKeys;

    if (stories === null) {
      storyId = fb.child('stories').push({
        'currentTitle': '',
        'storyScore': 0,
        'type': 'public',
        'dateCreated': Firebase.ServerValue.TIMESTAMP,
        'activityMeasure': 0
      }).key();
    } else {
      storyKeys = Object.keys(stories);
      storyId = storyKeys[storyKeys.length - 1];
    }
    fbEntries = fb.child('storyContent').child(storyId).child('entries');
    fbTurn = fb.child('storyCurrentTurn').child(storyId);
    storyTextElement.textContent = '';
    initialize();
    setUserLocation();
  });

  function initialize() {
    fbTurn.child('turnStartTime').on('value', function(snapshot) {
      startTurn(snapshot);
    });
    fbTurn.child('entries').on('child_added', function(snapshot) {
      addTurnEntry(snapshot);
    });
    fbTurn.on('value', function(snapshot) {
      updateTurn(snapshot);
    });
    fbEntries.on('child_added', function(snapshot) {
      addToStory(snapshot);
    });
  }

  // Initialize time at start of turn
  function startTurn(snapshot) {
    turnStartTime = snapshot.val();
    if (turnStartTime && !turnInProgress) {
      timer.textContent = Number(TURN_TIME) -
          Math.floor((new Date().getTime() + timeOffset - turnStartTime)/1000);
      setTimeout(decrementTimer, 1000);
      turnInProgress = true;
    }
  }

  // Set up adding entry to choices during turn
  function addTurnEntry(snapshot) {
    var turnEntry = snapshot.val();
    var turnEntryKey = snapshot.key();
    var entryCount, entryElement;

    entryCount = turnKeys.push(turnEntryKey);
    entryElement = querySelector('#entry' + entryCount);
    entryElement.textContent = turnEntry.entry;
    entryElement.style.display = 'block';
    querySelector('main').style.marginBottom = querySelector('#footer').clientHeight + 'px';
    if (entryCount >= 5) {
      storyInputElement.disabled = true;
      storyInputElement.textContent = '';
    }
    scrollToBottom();
  }

  // Winning word to storyContent on firebase
  function updateTurn(snapshot) {
    var currentTurn = snapshot.val();
    var k, key, score, winningEntry;

    if (currentTurn && currentTurn.winner) {
      for (k in currentTurn.winner) {
        if (!currentTurn.winner.hasOwnProperty(k)) {continue;}
        key = k;
        score = currentTurn.winner[key];
      }
      winningEntry = {};
      winningEntry[key] = {};
      winningEntry[key].entry = currentTurn.entries[key].entry;
      winningEntry[key].user = currentTurn.entries[key].user;
      winningEntry[key].entryScore = score;
      fbEntries.update(winningEntry);
    }
  }

  // Set up adding entry to story at end of turn
  function addToStory(snapshot) {
    var i, entryElement;
    var turnEntry = snapshot.val();

    storyTextElement.textContent += turnEntry.entry + ' ';
    querySelector('main').style.marginBottom = 0;
    for (i = 1; i <= 5; i++) {
      entryElement = querySelector('#entry' + i);
      entryElement.textContent = '';
      entryElement.style.display = 'none'; //classList.add('invisible');
    }
    storyInputElement.disabled = false;
    turnInProgress = false;
    fbTurn.remove();
    turnKeys = [];
    scrollToBottom();
  }

  function scrollToBottom() {
    window.scrollTo(0, querySelector('main').clientHeight);
  }

  // record what story the user is currently in
  function setUserLocation() {
    if (storyId && uid) {
      fb.child('people').child(uid).child('currentStory').set(storyId);
    }
  }

  // Enter an entry to start turn or add to current turn
  storyInputElement.addEventListener('keyup', function(e) {
    var entry, firstProVote;

    if (e.keyCode === 13) {
      entry = storyInputElement.value;
      firstProVote = {};
      firstProVote.pro = {};
      firstProVote.pro[uid] = true;
      if (!turnStartTime) {
        fbTurn.child('turnStartTime').set(Firebase.ServerValue.TIMESTAMP);
      }
      fbTurn.child('entries').push({
        'entry': entry,
        'entryVotes': firstProVote,
        'user': uid
      },
      function(error) {
        if (error) {
          console.log('Error during new word push: ' + error.toString());
        }
      });
      storyInputElement.value = '';
      //storyInputElement.disabled = true;  //uncomment before deploy
    }
  });

  storyInputElement.addEventListener('focus', function() {
    if (!loggedIn) {
      loginWindow.style.display = 'flex';
    }
  });

  authButton.addEventListener('click', function() {
    if (!loggedIn) {
      loginWindow.style.display = 'flex'; //classList.remove('invisible');
    } else {
      fb.unauth();
    }
  });

  googleLogin.addEventListener('click', function() {
    loginWindow.style.display = 'none'; //classList.add('invisible');
    // prefer pop-ups, so we don't navigate away from the page
    fb.authWithOAuthPopup('google', function(error, authData) {
      if (error) {
        if (error.code === 'TRANSPORT_UNAVAILABLE') {
          // fall-back to browser redirects, and pick up the session
          // automatically when we come back to the origin page
          fb.authWithOAuthRedirect('google', function(error) {
            console.log('Auth failure with error: ' + error);
          });
        }
      } else if (authData) {
        console.log(authData);
      }
    });
  });

  fb.onAuth(function(authData) {
    if (authData) {
      loggedIn = true;
      authButton.textContent = 'Logout';
      uid = authData.uid;
      showProfile(true, authData);
      recordAuth(authData);
    } else {
      authButton.textContent = 'Login';
      if (loggedIn) {
        showProfile(false);
      }
      loggedIn = false;
      uid = undefined;
    }
    setOnlineStatus();
    setUserLocation();
  });

  function showProfile(makeVisible, authData) {
    var profilePic = querySelector('#profilePic');
    var profileName = querySelector('#profileName');
    var profileGreeting = querySelector('#profileGreeting');

    if (makeVisible) {
      profileName.textContent = authData.google.displayName.split(' ')[0];
      profileGreeting.style.display = 'block'; //classList.remove('invisible');
      profilePic.setAttribute('src', authData.google.profileImageURL);
      profilePic.style.display = 'block'; //classList.remove('invisible');
    } else {
      profileGreeting.style.display = 'none'; //classList.add('invisible');
      profilePic.style.display = 'none'; //classList.add('invisible');
    }
  }

  function recordAuth(authData) {
    var fbUser = fb.child('people').child(uid);

    fbUser.once('value', function(snapshot) {
      if (!snapshot.val()) {
        // Use update instead of set in case there is a race condition with
        // currentStory: storyId
        fbUser.update({
          'userName': authData.google.displayName,
          'provider': 'google',
          'gameScore': 0
        });
      }
    });
  }

  function decrementTimer() {
    var timerNumber = Number(timer.textContent);
    if (timerNumber > 1) {
      timer.textContent = Number(timer.textContent) - 1;
      setTimeout(decrementTimer, 1000);
    } else {
      timer.textContent = '';
      selectWinner();
    }
  }

  function selectWinner() {
    fbTurn.once('value', function(snap) {
      console.log(snap.val());
    });
    fbTurn.transaction(function(currentData) {
      var prop, proObject, conObject, winner, key, winningKey;
      var candidateScore = 0, winningScore = -1;

      if (currentData === null) {return currentData;}
      for (key in currentData.entries) {
        if (!currentData.entries.hasOwnProperty(key)) {continue;}
        proObject = currentData.entries[key].entryVotes.pro;
        conObject = currentData.entries[key].entryVotes.con;
        for (prop in proObject) {
          candidateScore += 1;
        }
        for (prop in conObject) {
          candidateScore -= 1;
        }
        if (candidateScore > winningScore) {
          winningScore = candidateScore;
          winningKey = key;
        }
        candidateScore = 0;
      }
      winner = {};
      winner[winningKey] = winningScore;
      if (winningScore > -1) {
        currentData.winner = winner;
        return currentData;
      } else {
        return;
      }
    }, function(error, wasCommitted, snapshot) {
      console.log('Error: ' + error);
      console.log('Committed?: ' + wasCommitted);
      console.log('Result: ' + snapshot.val());
    }, false);
  }
})(document);<commit_msg>fixed multi-user problem<commit_after>(function (document) {
  'use strict';

  var querySelector = document.querySelector.bind(document);

  var TURN_TIME = '30';
  var storyId, fbEntries, fbTurn, connection, uid, connected, timeOffset, turnStartTime; //turnObject;
  var fb = new Firebase('https://moword.firebaseio.com');
  var fbConnected = fb.child('.info/connected');
  var storyTextElement = querySelector('#storyText');
  var storyInputElement = querySelector('#storyInput');
  var loginWindow = querySelector('#login');
  var googleLogin = querySelector('#googleLogin');
  var authButton = querySelector('#authButton');
  var loggedIn = false;
  var timer = querySelector('#timer');
  var turnKeys = [];
  var turnInProgress = false;

  fb.child('.info').child('serverTimeOffset').once('value', function(snap) {
    timeOffset = snap.val();
  });

  fbConnected.on('value', function(snap) {
    connected = snap.val();
    setOnlineStatus();
  });

  function setOnlineStatus() {
    if (connected && uid) {
      // We're connected and the user is authorized
      // add this device to the users connections list
      connection = fb.child('people').child(uid).child('online').push(true);
      connection.onDisconnect().remove();
    } else if (connection) {
      connection.remove();
    }
  }

  fb.child('stories').limitToLast(10).once('value', function(snapshot) {
    var stories = snapshot.val();
    var storyKeys;

    if (stories === null) {
      storyId = fb.child('stories').push({
        'currentTitle': '',
        'storyScore': 0,
        'type': 'public',
        'dateCreated': Firebase.ServerValue.TIMESTAMP,
        'activityMeasure': 0
      }).key();
    } else {
      storyKeys = Object.keys(stories);
      storyId = storyKeys[storyKeys.length - 1];
    }
    fbEntries = fb.child('storyContent').child(storyId).child('entries');
    fbTurn = fb.child('storyCurrentTurn').child(storyId);
    storyTextElement.textContent = '';
    initialize();
    setUserLocation();
  });

  function initialize() {
    console.log('initializing firebase callbacks');
    fbTurn.child('turnStartTime').on('value', function(snapshot) {
      startTurn(snapshot);
    });
    fbTurn.child('entries').on('child_added', function(snapshot) {
      addTurnEntry(snapshot);
    });
    fbTurn.on('value', function(snapshot) {
      updateTurn(snapshot);
    });
    fbEntries.on('child_added', function(snapshot) {
      addToStory(snapshot);
    });
  }

  // Initialize time at start of turn
  function startTurn(snapshot) {
    turnStartTime = snapshot.val();
    if (turnStartTime && !turnInProgress) {
      console.log('starting turn');
      timer.textContent = Number(TURN_TIME) -
          Math.floor((new Date().getTime() + timeOffset - turnStartTime)/1000);
      setTimeout(decrementTimer, 1000);
      turnInProgress = true;
    }
  }

  // Set up adding entry to choices during turn
  function addTurnEntry(snapshot) {
    console.log('adding entry to choices');
    var turnEntry = snapshot.val();
    var turnEntryKey = snapshot.key();
    var entryCount, entryElement;

    entryCount = turnKeys.push(turnEntryKey);
    entryElement = querySelector('#entry' + entryCount);
    entryElement.textContent = turnEntry.entry;
    entryElement.style.display = 'block';
    querySelector('main').style.marginBottom = querySelector('#footer').clientHeight + 'px';
    if (entryCount >= 5) {
      storyInputElement.disabled = true;
      storyInputElement.textContent = '';
    }
    scrollToBottom();
  }

  // Winning entry to storyContent on firebase
  function updateTurn(snapshot) {
    var currentTurn = snapshot.val();
    var i, entryElement, k, key, score, winningEntry;

    if (currentTurn && currentTurn.winner) {
      console.log('adding winning entry to storyContent');
      for (k in currentTurn.winner) {
        if (!currentTurn.winner.hasOwnProperty(k)) {continue;}
        key = k;
        score = currentTurn.winner[key];
      }
      winningEntry = {};
      winningEntry[key] = {};
      winningEntry[key].entry = currentTurn.entries[key].entry;
      winningEntry[key].user = currentTurn.entries[key].user;
      winningEntry[key].entryScore = score;
      fbEntries.update(winningEntry);
      fbTurn.remove();
    }
    // this must be a separate if statement so that all players get cleanup
    // from previous turn after fbTurn.remove() from another player above.
    if (currentTurn === null) {
      for (i = 1; i <= 5; i++) {
        entryElement = querySelector('#entry' + i);
        entryElement.textContent = '';
        entryElement.style.display = 'none'; //classList.add('invisible');
      }
      storyInputElement.disabled = false;
      turnInProgress = false;
      turnKeys = [];
      scrollToBottom();
      querySelector('main').style.marginBottom = 0;
    }
  }

  // Set up adding entry to story at end of turn
  function addToStory(snapshot) {
    console.log('adding entry to display');
    storyTextElement.textContent += snapshot.val().entry + ' ';
    scrollToBottom();
  }

  function scrollToBottom() {
    window.scrollTo(0, querySelector('main').clientHeight);
  }

  // record what story the user is currently in
  function setUserLocation() {
    if (storyId && uid) {
      fb.child('people').child(uid).child('currentStory').set(storyId);
    }
  }

  // Enter an entry to start turn or add to current turn
  storyInputElement.addEventListener('keyup', function(e) {
    var entry, firstProVote;

    if (e.keyCode === 13) {
      entry = storyInputElement.value;
      firstProVote = {};
      firstProVote.pro = {};
      firstProVote.pro[uid] = true;
      if (!turnStartTime) {
        fbTurn.child('turnStartTime').set(Firebase.ServerValue.TIMESTAMP);
      }
      fbTurn.child('entries').push({
        'entry': entry,
        'entryVotes': firstProVote,
        'user': uid
      },
      function(error) {
        if (error) {
          console.log('Error during new word push: ' + error.toString());
        }
      });
      storyInputElement.value = '';
      //storyInputElement.disabled = true;  //uncomment before deploy
    }
  });

  storyInputElement.addEventListener('focus', function() {
    if (!loggedIn) {
      loginWindow.style.display = 'flex';
    }
  });

  authButton.addEventListener('click', function() {
    if (!loggedIn) {
      loginWindow.style.display = 'flex'; //classList.remove('invisible');
    } else {
      fb.unauth();
    }
  });

  googleLogin.addEventListener('click', function() {
    loginWindow.style.display = 'none'; //classList.add('invisible');
    // prefer pop-ups, so we don't navigate away from the page
    fb.authWithOAuthPopup('google', function(error, authData) {
      if (error) {
        if (error.code === 'TRANSPORT_UNAVAILABLE') {
          // fall-back to browser redirects, and pick up the session
          // automatically when we come back to the origin page
          fb.authWithOAuthRedirect('google', function(error) {
            console.log('Auth failure with error: ' + error);
          });
        }
      } else if (authData) {
        console.log(authData);
      }
    });
  });

  fb.onAuth(function(authData) {
    if (authData) {
      loggedIn = true;
      authButton.textContent = 'Logout';
      uid = authData.uid;
      showProfile(true, authData);
      recordAuth(authData);
    } else {
      authButton.textContent = 'Login';
      if (loggedIn) {
        showProfile(false);
      }
      loggedIn = false;
      uid = undefined;
    }
    setOnlineStatus();
    setUserLocation();
  });

  function showProfile(makeVisible, authData) {
    var profilePic = querySelector('#profilePic');
    var profileName = querySelector('#profileName');
    var profileGreeting = querySelector('#profileGreeting');

    if (makeVisible) {
      profileName.textContent = authData.google.displayName.split(' ')[0];
      profileGreeting.style.display = 'block'; //classList.remove('invisible');
      profilePic.setAttribute('src', authData.google.profileImageURL);
      profilePic.style.display = 'block'; //classList.remove('invisible');
    } else {
      profileGreeting.style.display = 'none'; //classList.add('invisible');
      profilePic.style.display = 'none'; //classList.add('invisible');
    }
  }

  function recordAuth(authData) {
    var fbUser = fb.child('people').child(uid);

    fbUser.once('value', function(snapshot) {
      if (!snapshot.val()) {
        // Use update instead of set in case there is a race condition with
        // currentStory: storyId
        fbUser.update({
          'userName': authData.google.displayName,
          'provider': 'google',
          'gameScore': 0
        });
      }
    });
  }

  function decrementTimer() {
    var timerNumber = Number(timer.textContent);
    if (timerNumber > 1) {
      timer.textContent = Number(timer.textContent) - 1;
      setTimeout(decrementTimer, 1000);
    } else {
      timer.textContent = '';
      selectWinner();
    }
  }

  function selectWinner() {
    console.log('adding winner to storyCurrentTurn');
    /*fbTurn.once('value', function(snap) {
      console.log(snap.val());
    });*/
    fbTurn.transaction(function(currentData) {
      var prop, proObject, conObject, winner, key, winningKey;
      var candidateScore = 0, winningScore = -1;

      if (currentData === null) {return currentData;}
      for (key in currentData.entries) {
        if (!currentData.entries.hasOwnProperty(key)) {continue;}
        proObject = currentData.entries[key].entryVotes.pro;
        conObject = currentData.entries[key].entryVotes.con;
        for (prop in proObject) {
          candidateScore += 1;
        }
        for (prop in conObject) {
          candidateScore -= 1;
        }
        if (candidateScore > winningScore) {
          winningScore = candidateScore;
          winningKey = key;
        }
        candidateScore = 0;
      }
      winner = {};
      winner[winningKey] = winningScore;
      if (winningScore > -1) {
        currentData.winner = winner;
        return currentData;
      } else {
        return;
      }
    }, function(error, wasCommitted, snapshot) {
      console.log('Error: ' + error);
      console.log('Committed?: ' + wasCommitted);
      console.log('Result: ' + snapshot.val());
    }, false);
  }
})(document);<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';

const readjson = require('readjson');
const tryToCatch = require('try-to-catch');

const version = require('..');
const args = process.argv.slice(2);
const arg = args[0];
const pkgUp = require('pkg-up');

main()

async function main() {
    if (/^(-v|--version)$/.test(arg))
        return console.log('v' + require('../package').version);

    if (arg) {
        const [e, data] = await version(arg);

        if (e)
            return console.error(e.message);

        return console.log(data);
    }

    const name = await pkgUp();

    if (!name)
        return console.error('package.json: not found');

    const [error, info] = await tryToCatch(readjson, name);

    if (!error)
        return console.log(info.version || 'no version');

    if (error.code === 'ENOENT')
        return console.error('package.json: not found');

    return console.error('package.json:', error.message);
}

<commit_msg>fix(version) add tryToCatch<commit_after>#!/usr/bin/env node

'use strict';

const readjson = require('readjson');
const tryToCatch = require('try-to-catch');

const version = require('..');
const args = process.argv.slice(2);
const arg = args[0];
const pkgUp = require('pkg-up');

main()

async function main() {
    if (/^(-v|--version)$/.test(arg))
        return console.log('v' + require('../package').version);

    if (arg) {
        const [e, data] = await tryToCatch(version, arg);

        if (e)
            return console.error(e.message);

        return console.log(data);
    }

    const name = await pkgUp();

    if (!name)
        return console.error('package.json: not found');

    const [error, info] = await tryToCatch(readjson, name);

    if (!error)
        return console.log(info.version || 'no version');

    if (error.code === 'ENOENT')
        return console.error('package.json: not found');

    return console.error('package.json:', error.message);
}

<|endoftext|>


<commit_before>"use strict";

// Submission ID, S7755084
// Common Name, Black-bellied Whistling-Duck
// Scientific Name, Dendrocygna autumnalis
// Taxonomic Order, 215
// Count, X
// State/Province, US-TX
// County, Cameron
// Location, Brownsville
// Latitude, 25.911388
// Longitude, -97.4904876
// Date, 04-17-2004
// Time,
// Protocol, eBird - Casual Observation
// Duration (Min),
// All Obs Reported,
// Distance Traveled (km),
// Area Covered (ha),
// Number of Observers,
// Breeding Code,
// Species Comments,
// Checklist Comments

var gSightings = [];
var gChecklists = [];
var gEarliestSightingDateObject = null;
var gLatestSightingDateObject = null;
var gOmittedCommonNames = [];
var gLifeSightingsTaxonomic = [];
var gLifeSightingsChronological = [];
var gSightingsByYear = {};
var gEarliestSightingByCommonName = {};
var gLocations = [];
var gDates = [];
var gCustomDayNames = [];

function getEarliestSighting(sightingList) {
	sightingList.sort(function(a, b) { return a['DateObject'] - b['DateObject']; });
	return sightingList[0];
}

function getLatestSighting(sightingList) {
	sightingList.sort(function(a, b) { return b['DateObject'] - a['DateObject']; });
	return sightingList[0];
}

function getUniqueValues(sightingList, fieldName) {
	var values = [];

	for (var index = 1; index < sightingList.length; index++) {
		var aValue = sightingList[index][fieldName];
		if (values.indexOf(aValue) < 0) {
			values.push(aValue);
		}
	}

	return values;
};

function addDateObjects() {
	for (var index = 0; index < gSightings.length; index++) {
		var sighting = gSightings[index];

		if (sighting['Date']) {
			var pieces = sighting['Date'].split('-');
			var fixedDateString = [pieces[0], '/', pieces[1], '/', pieces[2]].join('');
			var newDate = new Date(fixedDateString);
			gSightings[index]['DateObject'] = newDate;

			if (gEarliestSightingDateObject == null || newDate < gEarliestSightingDateObject) {
				gEarliestSightingDateObject = newDate;
			}

			if (gLatestSightingDateObject == null || newDate > gLatestSightingDateObject) {
				gLatestSightingDateObject = newDate;
			}

			if (! gSightingsByYear[pieces[2]]) {
				gSightingsByYear[pieces[2]] = [];
			}
			gSightingsByYear[pieces[2]].push(sighting);

			var omit = gOmittedCommonNames.indexOf(sighting['Common Name']) >=0;

			if (! omit) {
				if (! gEarliestSightingByCommonName[sighting['Common Name']]) {
					gEarliestSightingByCommonName[sighting['Common Name']] = sighting;
				} else if (sighting.DateObject < gEarliestSightingByCommonName[sighting['Common Name']].DateObject) {
					gEarliestSightingByCommonName[sighting['Common Name']] = sighting;
				}
			}
		}
	}

	gSightings.sort(function(a, b) { return a['DateObject'] - b['DateObject']; });
}

function renderTemplate(inPrefix, inData) {

    var theTemplateScript = document.getElementById(inPrefix + '-template').innerHTML;
    var theTemplate = Handlebars.compile(theTemplateScript);
	var newDiv = document.createElement("div");
	newDiv.innerHTML = theTemplate(inData);

	var results = document.getElementById(inPrefix + '-results');
	while (results.firstChild) {
	    results.removeChild(results.firstChild);
	}

    // hide loading section
	document.getElementById('loading').classList.remove('visible');
	document.getElementById('loading').classList.add('hidden');

	// show rendered template
    results.appendChild(newDiv);
}

function showSection(inSelector) {
	var sections = document.querySelectorAll(inSelector);
	for (var index = 0; index < sections.length; index++) {
		sections[index].classList.remove('hidden');
		sections[index].classList.add('visible');
	}
}

function hideAllSections() {
	var sections = document.querySelectorAll('section.card');
	for (var index = 0; index < sections.length; index++) {
		sections[index].classList.remove('visible');
		sections[index].classList.add('hidden');
	}
}

function barGraphCountsForSightings(inData, inElement) {
	var labels = Object.keys(inData).map(function(k){return k;});
	var values = Object.keys(inData).map(function(k){return inData[k].length;});
	var values2 = Object.keys(inData).map(function(k){return getUniqueValues(inData[k], 'Common Name').length;});
	var values3 = Object.keys(inData).map(function(k){return getUniqueValues(inData[k], 'Location').length;});

	labels.unshift('x');
	values.unshift('sightings');
	values2.unshift('species');
	values3.unshift('locations');

	var chart = c3.generate({
		bindto: d3.select(inElement),
		data: {
			x: 'x',
			columns: [
				values,
				values2,
				values3,
				labels,
			],
			types: {
				sightings: 'line',
				species: 'line',
				locations: 'line'
			}
		}
	});
}

var routingMap = {
	'#home' : function() {
		renderTemplate('home', {
			numSightings: gSightings.length,
			sightingsByYear: gSightingsByYear,
			chartID: 'byYear',
			numChecklists: getUniqueValues(gSightings, 'Submission ID').length,
			earliest: gEarliestSightingDateObject,
			latest: gLatestSightingDateObject,
			owner: 'Bill Walker'
		});

		showSection('section#home');
	},
	'#chrono' : function() {
		gLifeSightingsChronological = Object.keys(gEarliestSightingByCommonName).map(function(k){return gEarliestSightingByCommonName[k]});
		gLifeSightingsChronological.sort(function(a, b) { return a['DateObject'] - b['DateObject']; });

		renderTemplate('chrono', {
			firstSightings: gLifeSightingsChronological
		});

		showSection('section#chrono');
	},
	'#trips' : function() {
		renderTemplate('trips', {
			trips: gDates,
			customDayNames: gCustomDayNames
		});

		showSection('section#trips');
	},
	'#trip' : function(inDate) {
		var tripSightings = gSightings.filter(function(s) { return s['Date'] == inDate; });

		renderTemplate('trip', {
			name: inDate,
			customName: gCustomDayNames[inDate],
			comments: getUniqueValues(tripSightings, 'Checklist Comments'),
			submissions: getUniqueValues(tripSightings, 'Submission ID'),
			sightings: tripSightings
		});

		showSection('section#trip');
	},
	'#locations' : function() {
		renderTemplate('locations', {
			locations: gLocations
		});

		showSection('section#locations');
	},
	'#location' : function(inLocationName) {
		var locationSightingsChronological = gSightings.filter(function(s) { return s['Location'] == inLocationName; });
		locationSightingsChronological.sort(function(a, b) { return b['DateObject'] - a['DateObject']; });

		var locationSightingsTaxonomic = locationSightingsChronological.slice(0);
		locationSightingsTaxonomic.sort(function(a, b) { return a['Taxonomic Order'] - b['Taxonomic Order']; });

		renderTemplate('location', {
			name: inLocationName,
			county: locationSightingsChronological[0]["County"],
			state: locationSightingsChronological[0]["State/Province"],
			locationSightingsTaxonomic: locationSightingsTaxonomic,
			longitude: locationSightingsChronological[0]["Longitude"],
			latitude: locationSightingsChronological[0]["Latitude"],
			dates: getUniqueValues(locationSightingsChronological, "Date"),
			taxons: getUniqueValues(locationSightingsTaxonomic, "Common Name")
		});

		showSection('section#location');
	},
	'#taxons' : function() {
		gLifeSightingsTaxonomic = Object.keys(gEarliestSightingByCommonName).map(function(k){return gEarliestSightingByCommonName[k]});
		gLifeSightingsTaxonomic.sort(function(a, b) { return a['Taxonomic Order'] - b['Taxonomic Order']; });

		renderTemplate('taxons', {

			lifeSightings: gLifeSightingsTaxonomic
		});

		showSection('section#taxons');
	},
	'#taxon' : function(inCommonName) {
		var taxonSightings = gSightings.filter(function(s) { return s['Common Name'] == inCommonName; });
		taxonSightings.sort(function(a, b) { return a['DateObject'] - b['DateObject']; });

		renderTemplate('taxon', {
			name: inCommonName,
			scientificName: taxonSightings[0]["Scientific Name"],
			sightings: taxonSightings
		});

		showSection('section#taxon');
	},
}

function routeBasedOnHash() {
	hideAllSections();

	// show loading section
	document.getElementById('loading').classList.add('visible');
	document.getElementById('loading').classList.remove('hidden');

	// On every hash change the render function is called with the new hash.
	// This is how the navigation of our app happens.
	var theHashParts = window.location.hash.split('/');
	console.log('changed', theHashParts[0], theHashParts[1]);

	if(routingMap[theHashParts[0]]) {
		routingMap[theHashParts[0]](decodeURI(theHashParts[1]));
	} else {
		console.log('not found', window.location.hash);
	}
}

function loadCustomDayNames() {
	var oReq = new XMLHttpRequest();
	oReq.addEventListener("load", function() {
	  gCustomDayNames = JSON.parse(this.responseText);
	  console.log('loaded custom day names', Object.keys(gCustomDayNames).length);
	});
	oReq.open("GET", "./data/day-names.json");
	oReq.send();
}

function loadOmittedCommonNames() {
	var oReq = new XMLHttpRequest();
	oReq.addEventListener("load", function() {
	  gOmittedCommonNames = JSON.parse(this.responseText);
	  console.log('loaded omitted common names', gOmittedCommonNames.length);
	});
	oReq.open("GET", "./data/omitted-common-names.json");
	oReq.send();
}

document.addEventListener("DOMContentLoaded", function(event) {
	console.log('start DOMContentLoaded');

	Handlebars.registerHelper('nicedate', function(inDate) {
		return new Handlebars.SafeString (
			d3.time.format("%b %d, %Y")(inDate)
		);
	});

	Handlebars.registerHelper('nicenumber', function(inNumber) {
		return new Handlebars.SafeString (
			d3.format(",d")(inNumber)
		);
	});

	Handlebars.registerHelper('bargraph', function(inData, inElement) {
		// per @digitarald use timeout to reorder helper after Handlebars templating
		window.setTimeout(function () { barGraphCountsForSightings(inData, '#' + inElement) }, 1);
	});

	console.log('end DOMContentLoaded');
});

Papa.parse("./data/ebird.csv", {
	download: true,
	header: true,
	complete: function(results) {
		gSightings = results.data;

		addDateObjects();

		gLocations = getUniqueValues(gSightings, 'Location');
		gDates = getUniqueValues(gSightings, 'Date');
		gChecklists = getUniqueValues(gSightings, 'Submission ID');

		routeBasedOnHash();
	}
});

window.onhashchange = routeBasedOnHash;

loadCustomDayNames();
loadOmittedCommonNames();

<commit_msg>redirect to https<commit_after>"use strict";

// Submission ID, S7755084
// Common Name, Black-bellied Whistling-Duck
// Scientific Name, Dendrocygna autumnalis
// Taxonomic Order, 215
// Count, X
// State/Province, US-TX
// County, Cameron
// Location, Brownsville
// Latitude, 25.911388
// Longitude, -97.4904876
// Date, 04-17-2004
// Time,
// Protocol, eBird - Casual Observation
// Duration (Min),
// All Obs Reported,
// Distance Traveled (km),
// Area Covered (ha),
// Number of Observers,
// Breeding Code,
// Species Comments,
// Checklist Comments

var gSightings = [];
var gChecklists = [];
var gEarliestSightingDateObject = null;
var gLatestSightingDateObject = null;
var gOmittedCommonNames = [];
var gLifeSightingsTaxonomic = [];
var gLifeSightingsChronological = [];
var gSightingsByYear = {};
var gEarliestSightingByCommonName = {};
var gLocations = [];
var gDates = [];
var gCustomDayNames = [];

function getEarliestSighting(sightingList) {
	sightingList.sort(function(a, b) { return a['DateObject'] - b['DateObject']; });
	return sightingList[0];
}

function getLatestSighting(sightingList) {
	sightingList.sort(function(a, b) { return b['DateObject'] - a['DateObject']; });
	return sightingList[0];
}

function getUniqueValues(sightingList, fieldName) {
	var values = [];

	for (var index = 1; index < sightingList.length; index++) {
		var aValue = sightingList[index][fieldName];
		if (values.indexOf(aValue) < 0) {
			values.push(aValue);
		}
	}

	return values;
};

function addDateObjects() {
	for (var index = 0; index < gSightings.length; index++) {
		var sighting = gSightings[index];

		if (sighting['Date']) {
			var pieces = sighting['Date'].split('-');
			var fixedDateString = [pieces[0], '/', pieces[1], '/', pieces[2]].join('');
			var newDate = new Date(fixedDateString);
			gSightings[index]['DateObject'] = newDate;

			if (gEarliestSightingDateObject == null || newDate < gEarliestSightingDateObject) {
				gEarliestSightingDateObject = newDate;
			}

			if (gLatestSightingDateObject == null || newDate > gLatestSightingDateObject) {
				gLatestSightingDateObject = newDate;
			}

			if (! gSightingsByYear[pieces[2]]) {
				gSightingsByYear[pieces[2]] = [];
			}
			gSightingsByYear[pieces[2]].push(sighting);

			var omit = gOmittedCommonNames.indexOf(sighting['Common Name']) >=0;

			if (! omit) {
				if (! gEarliestSightingByCommonName[sighting['Common Name']]) {
					gEarliestSightingByCommonName[sighting['Common Name']] = sighting;
				} else if (sighting.DateObject < gEarliestSightingByCommonName[sighting['Common Name']].DateObject) {
					gEarliestSightingByCommonName[sighting['Common Name']] = sighting;
				}
			}
		}
	}

	gSightings.sort(function(a, b) { return a['DateObject'] - b['DateObject']; });
}

function renderTemplate(inPrefix, inData) {

    var theTemplateScript = document.getElementById(inPrefix + '-template').innerHTML;
    var theTemplate = Handlebars.compile(theTemplateScript);
	var newDiv = document.createElement("div");
	newDiv.innerHTML = theTemplate(inData);

	var results = document.getElementById(inPrefix + '-results');
	while (results.firstChild) {
	    results.removeChild(results.firstChild);
	}

    // hide loading section
	document.getElementById('loading').classList.remove('visible');
	document.getElementById('loading').classList.add('hidden');

	// show rendered template
    results.appendChild(newDiv);
}

function showSection(inSelector) {
	var sections = document.querySelectorAll(inSelector);
	for (var index = 0; index < sections.length; index++) {
		sections[index].classList.remove('hidden');
		sections[index].classList.add('visible');
	}
}

function hideAllSections() {
	var sections = document.querySelectorAll('section.card');
	for (var index = 0; index < sections.length; index++) {
		sections[index].classList.remove('visible');
		sections[index].classList.add('hidden');
	}
}

function barGraphCountsForSightings(inData, inElement) {
	var labels = Object.keys(inData).map(function(k){return k;});
	var values = Object.keys(inData).map(function(k){return inData[k].length;});
	var values2 = Object.keys(inData).map(function(k){return getUniqueValues(inData[k], 'Common Name').length;});
	var values3 = Object.keys(inData).map(function(k){return getUniqueValues(inData[k], 'Location').length;});

	labels.unshift('x');
	values.unshift('sightings');
	values2.unshift('species');
	values3.unshift('locations');

	var chart = c3.generate({
		bindto: d3.select(inElement),
		data: {
			x: 'x',
			columns: [
				values,
				values2,
				values3,
				labels,
			],
			types: {
				sightings: 'line',
				species: 'line',
				locations: 'line'
			}
		}
	});
}

var routingMap = {
	'#home' : function() {
		renderTemplate('home', {
			numSightings: gSightings.length,
			sightingsByYear: gSightingsByYear,
			chartID: 'byYear',
			numChecklists: getUniqueValues(gSightings, 'Submission ID').length,
			earliest: gEarliestSightingDateObject,
			latest: gLatestSightingDateObject,
			owner: 'Bill Walker'
		});

		showSection('section#home');
	},
	'#chrono' : function() {
		gLifeSightingsChronological = Object.keys(gEarliestSightingByCommonName).map(function(k){return gEarliestSightingByCommonName[k]});
		gLifeSightingsChronological.sort(function(a, b) { return a['DateObject'] - b['DateObject']; });

		renderTemplate('chrono', {
			firstSightings: gLifeSightingsChronological
		});

		showSection('section#chrono');
	},
	'#trips' : function() {
		renderTemplate('trips', {
			trips: gDates,
			customDayNames: gCustomDayNames
		});

		showSection('section#trips');
	},
	'#trip' : function(inDate) {
		var tripSightings = gSightings.filter(function(s) { return s['Date'] == inDate; });

		renderTemplate('trip', {
			name: inDate,
			customName: gCustomDayNames[inDate],
			comments: getUniqueValues(tripSightings, 'Checklist Comments'),
			submissions: getUniqueValues(tripSightings, 'Submission ID'),
			sightings: tripSightings
		});

		showSection('section#trip');
	},
	'#locations' : function() {
		renderTemplate('locations', {
			locations: gLocations
		});

		showSection('section#locations');
	},
	'#location' : function(inLocationName) {
		var locationSightingsChronological = gSightings.filter(function(s) { return s['Location'] == inLocationName; });
		locationSightingsChronological.sort(function(a, b) { return b['DateObject'] - a['DateObject']; });

		var locationSightingsTaxonomic = locationSightingsChronological.slice(0);
		locationSightingsTaxonomic.sort(function(a, b) { return a['Taxonomic Order'] - b['Taxonomic Order']; });

		renderTemplate('location', {
			name: inLocationName,
			county: locationSightingsChronological[0]["County"],
			state: locationSightingsChronological[0]["State/Province"],
			locationSightingsTaxonomic: locationSightingsTaxonomic,
			longitude: locationSightingsChronological[0]["Longitude"],
			latitude: locationSightingsChronological[0]["Latitude"],
			dates: getUniqueValues(locationSightingsChronological, "Date"),
			taxons: getUniqueValues(locationSightingsTaxonomic, "Common Name")
		});

		showSection('section#location');
	},
	'#taxons' : function() {
		gLifeSightingsTaxonomic = Object.keys(gEarliestSightingByCommonName).map(function(k){return gEarliestSightingByCommonName[k]});
		gLifeSightingsTaxonomic.sort(function(a, b) { return a['Taxonomic Order'] - b['Taxonomic Order']; });

		renderTemplate('taxons', {

			lifeSightings: gLifeSightingsTaxonomic
		});

		showSection('section#taxons');
	},
	'#taxon' : function(inCommonName) {
		var taxonSightings = gSightings.filter(function(s) { return s['Common Name'] == inCommonName; });
		taxonSightings.sort(function(a, b) { return a['DateObject'] - b['DateObject']; });

		renderTemplate('taxon', {
			name: inCommonName,
			scientificName: taxonSightings[0]["Scientific Name"],
			sightings: taxonSightings
		});

		showSection('section#taxon');
	},
}

function routeBasedOnHash() {
	hideAllSections();

	// show loading section
	document.getElementById('loading').classList.add('visible');
	document.getElementById('loading').classList.remove('hidden');

	// On every hash change the render function is called with the new hash.
	// This is how the navigation of our app happens.
	var theHashParts = window.location.hash.split('/');
	console.log('changed', theHashParts[0], theHashParts[1]);

	if(routingMap[theHashParts[0]]) {
		routingMap[theHashParts[0]](decodeURI(theHashParts[1]));
	} else {
		console.log('not found', window.location.hash);
	}
}

function loadCustomDayNames() {
	var oReq = new XMLHttpRequest();
	oReq.addEventListener("load", function() {
	  gCustomDayNames = JSON.parse(this.responseText);
	  console.log('loaded custom day names', Object.keys(gCustomDayNames).length);
	});
	oReq.open("GET", "./data/day-names.json");
	oReq.send();
}

function loadOmittedCommonNames() {
	var oReq = new XMLHttpRequest();
	oReq.addEventListener("load", function() {
	  gOmittedCommonNames = JSON.parse(this.responseText);
	  console.log('loaded omitted common names', gOmittedCommonNames.length);
	});
	oReq.open("GET", "./data/omitted-common-names.json");
	oReq.send();
}

// REDIRECT to HTTPS!
var host = "wfwalker.github.io";
if ((host == window.location.host) && (window.location.protocol != "https:")) {
	window.location.protocol = "https";
} else {
	document.addEventListener("DOMContentLoaded", function(event) {
		console.log('start DOMContentLoaded');

		Handlebars.registerHelper('nicedate', function(inDate) {
			return new Handlebars.SafeString (
				d3.time.format("%b %d, %Y")(inDate)
			);
		});

		Handlebars.registerHelper('nicenumber', function(inNumber) {
			return new Handlebars.SafeString (
				d3.format(",d")(inNumber)
			);
		});

		Handlebars.registerHelper('bargraph', function(inData, inElement) {
			// per @digitarald use timeout to reorder helper after Handlebars templating
			window.setTimeout(function () { barGraphCountsForSightings(inData, '#' + inElement) }, 1);
		});

		console.log('end DOMContentLoaded');
	});

	Papa.parse("./data/ebird.csv", {
		download: true,
		header: true,
		complete: function(results) {
			gSightings = results.data;

			addDateObjects();

			gLocations = getUniqueValues(gSightings, 'Location');
			gDates = getUniqueValues(gSightings, 'Date');
			gChecklists = getUniqueValues(gSightings, 'Submission ID');

			routeBasedOnHash();
		}
	});

	window.onhashchange = routeBasedOnHash;

	loadCustomDayNames();
	loadOmittedCommonNames();
}

<|endoftext|>


<commit_before>#! /usr/bin/env node
/*eslint no-console: "off"*/
var program = require('starting');
var path = require('path');
var os = require('os');
var config = require('../lib/config');
var colors = require('colors/safe');

function getIpList() {
  var ipList = [];
  var ifaces = os.networkInterfaces();
  Object.keys(ifaces).forEach(function(ifname) {
    ifaces[ifname].forEach(function (iface) {
      if (iface.family == 'IPv4') {
        ipList.push(iface.address);
      }
    });
  });

  return ipList;
}

function error(msg) {
  console.log(colors.red(msg));
}

function warn(msg) {
  console.log(colors.yellow(msg));
}

function info(msg) {
  console.log(colors.green(msg));
}

function showUsage(isRunning, options, restart) {
  var port = options.port || config.port;
  if (isRunning) {
    warn('[!] ' + config.name + '@' + config.version + ' is running');
  } else {
    info('[i] ' + config.name + '@' + config.version + (restart ? ' restarted' : ' started'));
  }

  info('[i] First, use your device to visit the following URL list, gets the ' + colors.bold('IP') + ' of the URL you can visit:');
  info(getIpList().map(function(ip) {
    return '    http://' + colors.bold(ip) + (port ? ':' + port : '') + '/';
  }).join('\n'));

  warn('    Note: If the following URLs are unable to access, check the server\'s firewall settings');
  warn('          For more information, please visit ' + colors.bold('https://github.com/avwo/whistle'));
  info('[i] Second, configure your device to use ' + config.name + ' as its HTTP and HTTPS proxy on ' + colors.bold('IP:') + port);
  info('[i] Last, use ' + colors.bold('Chrome') + ' to visit ' + colors.bold('http://' + (options.localUIHost || config.localUIHost) + '/') + ' to get started');

  if (parseInt(process.version.slice(1), 10) < 6) {
    warn(colors.bold('\nWarning: The current Node version is too low, access https://nodejs.org to install the latest version, or may not be able to intercept HTTPS CONNECTs\n'));
  }
}

function showStartupInfo(err, options, debugMode, restart) {
  if (!err || err === true) {
    return showUsage(err, options, restart);
  }
  if (/listen EADDRINUSE/.test(err)) {
    error('[!] Failed to bind proxy port ' + (options.port || config.port) + ': The port is already in use');
    info('[i] Please check if ' + config.name + ' is already running, you can ' + (debugMode ? 'stop whistle with `w2 stop` first' : 'restart whistle with `w2 restart`'));
    info('    or if another application is using the port, you can change the port with ' + (debugMode ? '`w2 run -p newPort`\n' : '`w2 start -p newPort`\n'));
  } else if (err.code == 'EACCES' || err.code == 'EPERM') {
    error('[!] Cannot start ' + config.name + ' owned by root');
    info('[i] Try to run command with `sudo`\n');
  }

  error(err.stack ? 'Date: ' + new Date().toLocaleString() + '\n' + err.stack : err);
}

program.setConfig({
  main: function(options) {
    var hash = options && options.storage && encodeURIComponent(options.storage);
    return path.join(__dirname, '../index.js') + (hash ? '#' + hash + '#' : '');
  },
  name: config.name,
  version: config.version,
  runCallback: function(err, options) {
    if (err) {
      showStartupInfo(err, options, true);
      return;
    }
    showUsage(false, options);
    console.log('Press [Ctrl+C] to stop ' + config.name + '...');
  },
  startCallback: showStartupInfo,
  restartCallback: function(err, options) {
    showStartupInfo(err, options, false, true);
  },
  stopCallback: function(err) {
    if (err === true) {
      info('[i] ' + config.name + ' killed.');
    } else if (err) {
      if (err.code === 'EPERM') {
        error('[!] Cannot kill ' + config.name + ' owned by root');
        info('[i] Try to run command with `sudo`');
      } else {
        error('[!] ' + err.message);
      }
    } else {
      warn('[!] No running ' + config.name);
    }
  }
});

program
  .option('-D, --baseDir [baseDir]', 'the base dir of config data', String, undefined)
  .option('-A, --ATS', 'generate Root CA for iOS ATS (Node >= 6 is required)')
  .option('-z, --certDir [directory]', 'custom certificate path', String, undefined)
  .option('-l, --localUIHost [hostname]', 'local ui host (' + config.localUIHost + ' by default)', String, undefined)
  .option('-L, --pluginHost [hostname]', 'plugin ui host (as: "script=a.b.com&vase=x.y.com")', String, undefined)
  .option('-n, --username [username]', 'the username of ' + config.name, String, undefined)
  .option('-w, --password [password]', 'the password of ' + config.name, String, undefined)
  .option('-N, --guestName [username]', 'the guest name', String, undefined)
  .option('-W, --guestPassword [password]', 'the guest password', String, undefined)
  .option('-s, --sockets [number]', 'max sockets (' + config.sockets + ' by default)', parseInt, undefined)
  .option('-S, --storage [newStorageDir]', 'the new local storage directory', String, undefined)
  .option('-C, --copy [storageDir]', 'copy storageDir to newStorageDir', String, undefined)
  .option('-c, --dnsCache [time]', 'the cache time of DNS (30000ms by default)', String, undefined)
  .option('-H, --host [host]', config.name + ' listening host(:: or 0.0.0.0 by default)', String, undefined)
  .option('-p, --port [port]', config.name + ' listening port (' + config.port + ' by default)', parseInt, undefined)
  .option('-P, --uiport [uiport]', config.name + ' ui port (' + (config.port + 1) + ' by default)', parseInt, undefined)
  .option('-m, --middlewares [script path or module name]', 'express middlewares path (as: xx,yy/zz.js)', String, undefined)
  .option('-M, --mode [mode]', 'the whistle mode (as: pureProxy|debug|multiEnv)', String, undefined)
  .option('-u, --uipath [script path]', 'web ui plugin path', String, undefined)
  .option('-t, --timeout [ms]', 'request timeout (' + config.timeout + ' ms by default)', parseInt, undefined)
  .option('-e, --extra [extraData]', 'extra data for plugin', String, undefined)
  .option('-f, --secureFilter [secureFilter]', 'the script path of secure filter', String, undefined)
  .option('-R, --reqCacheSize [reqCacheSize]', 'the cache size of request data (512 by default)', String, undefined)
  .option('-F, --frameCacheSize [frameCacheSize]', 'the cache size of socket frames (512 by default)', String, undefined)
  .parse(process.argv);
<commit_msg>refactor: add comment<commit_after>#! /usr/bin/env node
/*eslint no-console: "off"*/
var program = require('starting');
var path = require('path');
var os = require('os');
var config = require('../lib/config');
var colors = require('colors/safe');

function getIpList() {
  var ipList = [];
  var ifaces = os.networkInterfaces();
  Object.keys(ifaces).forEach(function(ifname) {
    ifaces[ifname].forEach(function (iface) {
      if (iface.family == 'IPv4') {
        ipList.push(iface.address);
      }
    });
  });

  return ipList;
}

function error(msg) {
  console.log(colors.red(msg));
}

function warn(msg) {
  console.log(colors.yellow(msg));
}

function info(msg) {
  console.log(colors.green(msg));
}

function showUsage(isRunning, options, restart) {
  var port = options.port || config.port;
  if (isRunning) {
    warn('[!] ' + config.name + '@' + config.version + ' is running');
  } else {
    info('[i] ' + config.name + '@' + config.version + (restart ? ' restarted' : ' started'));
  }

  info('[i] First, use your device to visit the following URL list, gets the ' + colors.bold('IP') + ' of the URL you can visit:');
  info(getIpList().map(function(ip) {
    return '    http://' + colors.bold(ip) + (port ? ':' + port : '') + '/';
  }).join('\n'));

  warn('    Note: If the following URLs are unable to access, check the server\'s firewall settings');
  warn('          For more information, please visit ' + colors.bold('https://github.com/avwo/whistle'));
  info('[i] Second, configure your device to use ' + config.name + ' as its HTTP and HTTPS proxy on ' + colors.bold('IP:') + port);
  info('[i] Last, use ' + colors.bold('Chrome') + ' to visit ' + colors.bold('http://' + (options.localUIHost || config.localUIHost) + '/') + ' to get started');

  if (parseInt(process.version.slice(1), 10) < 6) {
    warn(colors.bold('\nWarning: The current Node version is too low, access https://nodejs.org to install the latest version, or may not be able to intercept HTTPS CONNECTs\n'));
  }
}

function showStartupInfo(err, options, debugMode, restart) {
  if (!err || err === true) {
    return showUsage(err, options, restart);
  }
  if (/listen EADDRINUSE/.test(err)) {
    error('[!] Failed to bind proxy port ' + (options.port || config.port) + ': The port is already in use');
    info('[i] Please check if ' + config.name + ' is already running, you can ' + (debugMode ? 'stop whistle with `w2 stop` first' : 'restart whistle with `w2 restart`'));
    info('    or if another application is using the port, you can change the port with ' + (debugMode ? '`w2 run -p newPort`\n' : '`w2 start -p newPort`\n'));
  } else if (err.code == 'EACCES' || err.code == 'EPERM') {
    error('[!] Cannot start ' + config.name + ' owned by root');
    info('[i] Try to run command with `sudo`\n');
  }

  error(err.stack ? 'Date: ' + new Date().toLocaleString() + '\n' + err.stack : err);
}

program.setConfig({
  main: function(options) {
    var hash = options && options.storage && encodeURIComponent(options.storage);
    return path.join(__dirname, '../index.js') + (hash ? '#' + hash + '#' : '');
  },
  name: config.name,
  version: config.version,
  runCallback: function(err, options) {
    if (err) {
      showStartupInfo(err, options, true);
      return;
    }
    showUsage(false, options);
    console.log('Press [Ctrl+C] to stop ' + config.name + '...');
  },
  startCallback: showStartupInfo,
  restartCallback: function(err, options) {
    showStartupInfo(err, options, false, true);
  },
  stopCallback: function(err) {
    if (err === true) {
      info('[i] ' + config.name + ' killed.');
    } else if (err) {
      if (err.code === 'EPERM') {
        error('[!] Cannot kill ' + config.name + ' owned by root');
        info('[i] Try to run command with `sudo`');
      } else {
        error('[!] ' + err.message);
      }
    } else {
      warn('[!] No running ' + config.name);
    }
  }
});

program
  // 设置配置的存储根路径
  .option('-D, --baseDir [baseDir]', 'the base dir of config data', String, undefined)
  // 设置自定义证书存储目录
  .option('-z, --certDir [directory]', 'custom certificate path', String, undefined)
  // 设置访问抓包配置界面的域名(默认为local.whistlejs.com)
  .option('-l, --localUIHost [hostname]', 'local ui host (' + config.localUIHost + ' by default)', String, undefined)
  // 设置访问插件的域名(如："script=a.b.com&vase=x.y.com")
  .option('-L, --pluginHost [hostname]', 'plugin ui host (as: "script=a.b.com&vase=x.y.com")', String, undefined)
  // 设置访问抓包配置界面的用户名和密码
  .option('-n, --username [username]', 'the username of ' + config.name, String, undefined)
  // 设置访问抓包配置界面的密码
  .option('-w, --password [password]', 'the password of ' + config.name, String, undefined)
  // 设置访问抓包配置界面的访客名(该账号只能查看抓包不能配置规则)
  .option('-N, --guestName [username]', 'the guest name', String, undefined)
  // 设置访问抓包配置界面的访客码(该账号只能查看抓包不能配置规则)
  .option('-W, --guestPassword [password]', 'the guest password', String, undefined)
  // 设置每个域名缓存长连接数量(默认为60)
  .option('-s, --sockets [number]', 'max sockets (' + config.sockets + ' by default)', parseInt, undefined)
  // 设置配置的存储目录(每个目录只能启动一个实例)
  .option('-S, --storage [newStorageDir]', 'the new local storage directory', String, undefined)
  // 拷贝指定目录的配置到新目录
  .option('-C, --copy [storageDir]', 'copy storageDir to newStorageDir', String, undefined)
  // dns缓存时间(默认为30000ms)
  .option('-c, --dnsCache [time]', 'the cache time of DNS (30000ms by default)', String, undefined)
  // 设置启动监听的网卡(默认为所有网卡)
  .option('-H, --host [host]', config.name + ' listening host(:: or 0.0.0.0 by default)', String, undefined)
  // 设置启动监听的端口(默认为8899)
  .option('-p, --port [port]', config.name + ' listening port (' + config.port + ' by default)', parseInt, undefined)
  // 设置抓包配置界面监听的端口(默认为8900)
  .option('-P, --uiport [uiport]', config.name + ' ui port (' + (config.port + 1) + ' by default)', parseInt, undefined)
  // 设置启动时加载的express中间件
  .option('-m, --middlewares [script path or module name]', 'express middlewares path (as: xx,yy/zz.js)', String, undefined)
  // 设置启动模式(供扩展使用，如：pureProxy|debug|multiEnv)
  .option('-M, --mode [mode]', 'the whistle mode (as: pureProxy|debug|multiEnv)', String, undefined)
  // 设置自定义ui界面的路径
  .option('-u, --uipath [script path]', 'web ui plugin path', String, undefined)
  // 设置超时时间(默认为60000ms)
  .option('-t, --timeout [ms]', 'request timeout (' + config.timeout + ' ms by default)', parseInt, undefined)
  // 设置传给各个插件的参数
  .option('-e, --extra [extraData]', 'extra data for plugin', String, undefined)
  // 设置安全过滤器
  .option('-f, --secureFilter [secureFilter]', 'the script path of secure filter', String, undefined)
  // 设置服务端缓存请求数据的条数(默认为512)
  .option('-R, --reqCacheSize [reqCacheSize]', 'the cache size of request data (512 by default)', String, undefined)
  // 设置服务端缓存所有WebSocket和Socket请求的帧数(默认为512)
  .option('-F, --frameCacheSize [frameCacheSize]', 'the cache size of socket frames (512 by default)', String, undefined)
  .parse(process.argv);
<|endoftext|>


<commit_before>'use strict';

var regexIso8601 =
  /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{1,})(Z|([\-+])(\d{2}):(\d{2}))?$/;
// Matches YYYY-MM-ddThh:mm:ss.sssZ where .sss is optional
//var regexIso8601 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/

function convertDateStringsToDates(input) {
  // Ignore things that aren't objects.
  if (typeof input !== 'object') {
    return input;
  }

  for (var key in input) {
    if (!input.hasOwnProperty(key)) {
      continue;
    }

    var value = input[key];
    var match;
    // Check for string properties which look like dates.
    if (typeof value === 'string' && (match = value.match(regexIso8601))) {
      var milliseconds = Date.parse(match[0]);
      if (!isNaN(milliseconds)) {
        input[key] = new Date(milliseconds);
      }
    } else if (typeof value === 'object') {
      // Recurse into object
      input[key] = convertDateStringsToDates(value);
    }
  }
  return input;
}

/**
 */
angular
  .module('openolitor', [
    'ngAnimate',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngTouch',
    'ngTable',
    'ngFileSaver',
    'ui.bootstrap',
    'ui.bootstrap.datetimepicker',
    'color.picker',
    'ipCookie',
    'frapontillo.bootstrap-switch',
    'gettext',
    'ngHamburger',
    'angularMoment',
    'ngFileUpload'
  ])
  .constant('API_URL', '@@API_URL')
  .constant('API_WS_URL', '@@API_WS_URL')
  .constant('BUILD_NR', '@@BUILD_NR')
  .constant('LIEFERRHYTHMEN', {
    WOECHENTLICH: 'Woechentlich',
    ZWEIWOECHENTLICH: 'Zweiwoechentlich',
    MONATLICH: 'Monatlich',
    UNREGELMAESSIG: 'Unregelmaessig'
  })
  .constant('PREISEINHEITEN', {
    //JAHR: 'Jahr',
    //QUARTAL: 'Quartal',
    //MONAT: 'Monat',
    LIEFERUNG: 'Lieferung'
      //ABO: 'Aboende'
  })
  .constant('VERTRIEBSARTEN', {
    DEPOTLIEFERUNG: 'Depotlieferung',
    HEIMLIEFERUNG: 'Heimlieferung',
    POSTLIEFERUNG: 'Postlieferung'
  })
  .constant('LAUFZEITEINHEITEN', {
    UNBESCHRAENKT: 'Unbeschraenkt',
    LIEFERUNGEN: 'Lieferungen',
    MONATE: 'Monate'
  })
  .constant('ANREDE', {
    HERR: 'Herr',
    FRAU: 'Frau'
  })
  .constant('ABOTYPEN', {
    DEPOTLIEFERUNGABO: 'DepotlieferungAbo',
    HEIMLIEFERUNGABO: 'HeimlieferungAbo',
    POSTLIEFERUNGABO: 'PostlieferungAbo'
  })
  .constant('LIEFERSTATUS', {
    OFFEN: 'Offen',
    INBEARBEITUNG: 'InBearbeitung',
    BEARBEITET: 'Bearbeitet'
  })
  .constant('LIEFEREINHEIT', {
    STUECK: 'Stueck',
    BUND: 'Bund',
    GRAMM: 'Gramm',
    KILOGRAMM: 'Kilogramm',
  })
  .constant('ABOTYPEN_ARRAY', ['DepotlieferungAbo', 'HeimlieferungAbo',
    'PostlieferungAbo'
  ])
  .constant('LIEFERZEITPUNKTE', {
    MONTAG: {
      id: 'Montag',
      label: {
        long: 'Montag',
        short: 'MO'
      },
      value: 1
    },
    DIENSTAG: {
      id: 'Dienstag',
      label: {
        long: 'Dienstag',
        short: 'DI'
      },
      value: 2
    },
    MITTWOCH: {
      id: 'Mittwoch',
      label: {
        long: 'Mittwoch',
        short: 'MI'
      },
      value: 3
    },
    DONNERSTAG: {
      id: 'Donnerstag',
      label: {
        long: 'Donnerstag',
        short: 'DO'
      },
      value: 4
    },
    FREITAG: {
      id: 'Freitag',
      label: {
        long: 'Freitag',
        short: 'FR'
      },
      value: 5
    },
    SAMSTAG: {
      id: 'Samstag',
      label: {
        long: 'Samstag',
        short: 'SA'
      },
      value: 6
    },
    SONNTAG: {
      id: 'Sonntag',
      label: {
        long: 'Sonntag',
        short: 'SO'
      },
      value: 7
    }
  })
  .constant('MONATE', {
    JANUAR: {
      id: 'Januar',
      label: {
        long: 'Januar',
        short: 'Jan'
      },
      value: 1
    },
    FEBRUAR: {
      id: 'Februar',
      label: {
        long: 'Februar',
        short: 'Feb'
      },
      value: 2
    },
    MAERZ: {
      id: 'Maerz',
      label: {
        long: 'März',
        short: 'Mar'
      },
      value: 3
    },
    APRIL: {
      id: 'April',
      label: {
        long: 'April',
        short: 'Apr'
      },
      value: 4
    },
    MAI: {
      id: 'Mai',
      label: {
        long: 'Mai',
        short: 'Mai'
      },
      value: 5
    },
    JUNI: {
      id: 'Juni',
      label: {
        long: 'Juni',
        short: 'Jun'
      },
      value: 6
    },
    JULI: {
      id: 'Juli',
      label: {
        long: 'Juli',
        short: 'Jul'
      },
      value: 7
    },
    AUGUST: {
      id: 'August',
      label: {
        long: 'August',
        short: 'Aug'
      },
      value: 8
    },
    SEPTEMBER: {
      id: 'September',
      label: {
        long: 'September',
        short: 'Sep'
      },
      value: 9
    },
    OKTOBER: {
      id: 'Oktober',
      label: {
        long: 'Oktober',
        short: 'Okt'
      },
      value: 10
    },
    NOVEMBER: {
      id: 'November',
      label: {
        long: 'November',
        short: 'Nov'
      },
      value: 11
    },
    DEZEMBER: {
      id: 'Dezember',
      label: {
        long: 'Dezember',
        short: 'Dez'
      },
      value: 12
    }
  })
  .constant('PENDENZSTATUS', {
    AUSSTEHEND: 'Ausstehend',
    ERLEDIGT: 'Erledigt',
    NICHTERLEDIGT: 'NichtErledigt'
  })
  .run(function($rootScope, $location) {
    $rootScope.location = $location;
  })
  .factory('checkSize', ['$rootScope', '$window', function($rootScope, $window) {
    return function() {
      if ($window.innerWidth >= 1200) {
        $rootScope.tgState = true;
      }
    };
  }])
  .factory('exportTable', ['FileSaver', function(FileSaver) {
    return function(elementId, fileName) {
      var blob = new Blob([angular.element(elementId).html()], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
      });
      FileSaver.saveAs(blob, fileName);
    };
  }])
  .factory('cloneObj', function() {
    var cloneObjFun = function(obj) {
      if (null === obj || 'object' !== typeof obj) {
        return obj;
      }
      var copy = obj.constructor();
      for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) {
          copy[attr] = cloneObjFun(obj[attr]);
        }
      }
      return copy;
    };
    return cloneObjFun;
  })
  .factory('msgBus', ['$rootScope', function($rootScope) {
    var msgBus = {};
    msgBus.emitMsg = function(msg) {
      $rootScope.$emit(msg.type, msg);
    };
    msgBus.onMsg = function(msg, scope, func) {
      var unbind = $rootScope.$on(msg, func);
      scope.$on('$destroy', unbind);
    };
    return msgBus;
  }])
  .run(['ooClientMessageService', function(clientMessageService) {
    console.log('Start clientMessageService');
    clientMessageService.start();
  }])
  .config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.transformResponse.push(function(responseData) {
      return convertDateStringsToDates(responseData);
    });
  }])
  .config(['$provide', function($provide) {
    $provide.decorator('$exceptionHandler', ['$log', '$injector',
      function(
        $log, $injector) {
        return function(exception) {
          // using the injector to retrieve scope and timeout, otherwise circular dependency
          var $rootScope = $injector.get('$rootScope');
          var alertService = $injector.get('alertService');

          $rootScope.$removeAlert = alertService.removeAlert();
          alertService.addAlert('error', exception.message);

          // log error default style
          $log.error.apply($log, arguments);
        };
      }
    ]);
  }])
  .filter('fromNow', function() {
    return function(input) {
      //TODO: replace with current locale
      moment.updateLocale('de');
      return moment(input).fromNow();
    };
  })
  .config(function($routeProvider) {
    $routeProvider
      .when('/', {
        redirectTo: '/abos'
      })
      .when('/abotypen', {
        templateUrl: 'scripts/abotypen/overview/abotypenoverview.html',
        controller: 'AbotypenOverviewController',
        name: 'AbotypenOverview'
      })
      .when('/abotypen/new', {
        templateUrl: 'scripts/abotypen/detail/abotypendetail.html',
        controller: 'AbotypenDetailController',
        name: 'AbotypenDetail'
      })
      .when('/abotypen/:id', {
        templateUrl: 'scripts/abotypen/detail/abotypendetail.html',
        controller: 'AbotypenDetailController',
        name: 'AbotypenDetail'
      })
      .when('/kunden', {
        templateUrl: 'scripts/kunden/overview/kundenoverview.html',
        controller: 'KundenOverviewController',
        name: 'KundenOverview'
      })
      .when('/kunden/new', {
        templateUrl: 'scripts/kunden/detail/kundendetail.html',
        controller: 'KundenDetailController',
        name: 'KundeDetail'
      })
      .when('/kunden/:id', {
        templateUrl: 'scripts/kunden/detail/kundendetail.html',
        controller: 'KundenDetailController',
        name: 'KundeDetail'
      })
      .when('/kunden/:kundeId/abos/:id', {
        templateUrl: 'scripts/abos/detail/abosdetail.html',
        controller: 'AbosDetailController',
        name: 'AbosDetail'
      })
      .when('/produzenten', {
        templateUrl: 'scripts/produzenten/overview/produzentenoverview.html',
        controller: 'ProduzentenOverviewController',
        name: 'ProduzentenOverview'
      })
      .when('/produzenten/new', {
        templateUrl: 'scripts/produzenten/detail/produzentendetail.html',
        controller: 'ProduzentenDetailController',
        name: 'ProduzentenDetail'
      })
      .when('/produzenten/:id', {
        templateUrl: 'scripts/produzenten/detail/produzentendetail.html',
        controller: 'ProduzentenDetailController',
        name: 'ProduzentenDetail'
      })
      .when('/produzenten/:produzentId/abos/:id', {
        templateUrl: 'scripts/abos/detail/abosdetail.html',
        controller: 'AbosDetailController',
        name: 'AbosDetail'
      })
      .when('/produkte', {
        templateUrl: 'scripts/produkte/overview/produkteoverview.html',
        controller: 'ProdukteOverviewController',
        name: 'ProdukteOverview'
      })
      .when('/depots', {
        templateUrl: 'scripts/depots/overview/depotsoverview.html',
        controller: 'DepotsOverviewController',
        name: 'DepotsOverview'
      })
      .when('/depots/:id', {
        templateUrl: 'scripts/depots/detail/depotsdetail.html',
        controller: 'DepotsDetailController',
        name: 'DepotsDetail'
      })
      .when('/abos', {
        templateUrl: 'scripts/abos/overview/abosoverview.html',
        controller: 'AbosOverviewController',
        name: 'AbosOverview'
      })
      .when('/abos/:id', {
        templateUrl: 'scripts/abos/detail/abosdetail.html',
        controller: 'AbosDetailController',
        name: 'AbosDetail',
        resolve: {
          createKundeId: function() {
            return undefined;
          }
        }
      })
      .when('/touren', {
        templateUrl: 'scripts/touren/overview/tourenoverview.html',
        controller: 'TourenOverviewController',
        name: 'TourenOverview'
      })
      .when('/pendenzen', {
        templateUrl: 'scripts/pendenzen/overview/pendenzenoverview.html',
        controller: 'PendenzenOverviewController',
        name: 'PendenzenOverview'
      })
      .when('/korbplanung', {
        templateUrl: 'scripts/korbplanung/overview/korbplanungoverview.html',
        controller: 'KorbplanungOverviewController',
        name: 'KorbplanungDetail'
      })
      .when('/korbplanung/:id', {
        templateUrl: 'scripts/korbplanung/detail/korbplanungdetail.html',
        controller: 'KorbplanungDetailController',
        name: 'KorbplanungOverview'
      })
      .when('/settings', {
        templateUrl: 'scripts/projekt/settings/projektsettings.html',
        controller: 'ProjektSettingsController',
        name: 'ProjektSettings'
      })
      .otherwise({
        templateUrl: 'scripts/not-found.html'
      });
  });
<commit_msg>adjusted method call<commit_after>'use strict';

var regexIso8601 =
  /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{1,})(Z|([\-+])(\d{2}):(\d{2}))?$/;
// Matches YYYY-MM-ddThh:mm:ss.sssZ where .sss is optional
//var regexIso8601 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z$/

function convertDateStringsToDates(input) {
  // Ignore things that aren't objects.
  if (typeof input !== 'object') {
    return input;
  }

  for (var key in input) {
    if (!input.hasOwnProperty(key)) {
      continue;
    }

    var value = input[key];
    var match;
    // Check for string properties which look like dates.
    if (typeof value === 'string' && (match = value.match(regexIso8601))) {
      var milliseconds = Date.parse(match[0]);
      if (!isNaN(milliseconds)) {
        input[key] = new Date(milliseconds);
      }
    } else if (typeof value === 'object') {
      // Recurse into object
      input[key] = convertDateStringsToDates(value);
    }
  }
  return input;
}

/**
 */
angular
  .module('openolitor', [
    'ngAnimate',
    'ngResource',
    'ngRoute',
    'ngSanitize',
    'ngTouch',
    'ngTable',
    'ngFileSaver',
    'ui.bootstrap',
    'ui.bootstrap.datetimepicker',
    'color.picker',
    'ipCookie',
    'frapontillo.bootstrap-switch',
    'gettext',
    'ngHamburger',
    'angularMoment',
    'ngFileUpload'
  ])
  .constant('API_URL', '@@API_URL')
  .constant('API_WS_URL', '@@API_WS_URL')
  .constant('BUILD_NR', '@@BUILD_NR')
  .constant('LIEFERRHYTHMEN', {
    WOECHENTLICH: 'Woechentlich',
    ZWEIWOECHENTLICH: 'Zweiwoechentlich',
    MONATLICH: 'Monatlich',
    UNREGELMAESSIG: 'Unregelmaessig'
  })
  .constant('PREISEINHEITEN', {
    //JAHR: 'Jahr',
    //QUARTAL: 'Quartal',
    //MONAT: 'Monat',
    LIEFERUNG: 'Lieferung'
      //ABO: 'Aboende'
  })
  .constant('VERTRIEBSARTEN', {
    DEPOTLIEFERUNG: 'Depotlieferung',
    HEIMLIEFERUNG: 'Heimlieferung',
    POSTLIEFERUNG: 'Postlieferung'
  })
  .constant('LAUFZEITEINHEITEN', {
    UNBESCHRAENKT: 'Unbeschraenkt',
    LIEFERUNGEN: 'Lieferungen',
    MONATE: 'Monate'
  })
  .constant('ANREDE', {
    HERR: 'Herr',
    FRAU: 'Frau'
  })
  .constant('ABOTYPEN', {
    DEPOTLIEFERUNGABO: 'DepotlieferungAbo',
    HEIMLIEFERUNGABO: 'HeimlieferungAbo',
    POSTLIEFERUNGABO: 'PostlieferungAbo'
  })
  .constant('LIEFERSTATUS', {
    OFFEN: 'Offen',
    INBEARBEITUNG: 'InBearbeitung',
    BEARBEITET: 'Bearbeitet'
  })
  .constant('LIEFEREINHEIT', {
    STUECK: 'Stueck',
    BUND: 'Bund',
    GRAMM: 'Gramm',
    KILOGRAMM: 'Kilogramm',
  })
  .constant('ABOTYPEN_ARRAY', ['DepotlieferungAbo', 'HeimlieferungAbo',
    'PostlieferungAbo'
  ])
  .constant('LIEFERZEITPUNKTE', {
    MONTAG: {
      id: 'Montag',
      label: {
        long: 'Montag',
        short: 'MO'
      },
      value: 1
    },
    DIENSTAG: {
      id: 'Dienstag',
      label: {
        long: 'Dienstag',
        short: 'DI'
      },
      value: 2
    },
    MITTWOCH: {
      id: 'Mittwoch',
      label: {
        long: 'Mittwoch',
        short: 'MI'
      },
      value: 3
    },
    DONNERSTAG: {
      id: 'Donnerstag',
      label: {
        long: 'Donnerstag',
        short: 'DO'
      },
      value: 4
    },
    FREITAG: {
      id: 'Freitag',
      label: {
        long: 'Freitag',
        short: 'FR'
      },
      value: 5
    },
    SAMSTAG: {
      id: 'Samstag',
      label: {
        long: 'Samstag',
        short: 'SA'
      },
      value: 6
    },
    SONNTAG: {
      id: 'Sonntag',
      label: {
        long: 'Sonntag',
        short: 'SO'
      },
      value: 7
    }
  })
  .constant('MONATE', {
    JANUAR: {
      id: 'Januar',
      label: {
        long: 'Januar',
        short: 'Jan'
      },
      value: 1
    },
    FEBRUAR: {
      id: 'Februar',
      label: {
        long: 'Februar',
        short: 'Feb'
      },
      value: 2
    },
    MAERZ: {
      id: 'Maerz',
      label: {
        long: 'März',
        short: 'Mar'
      },
      value: 3
    },
    APRIL: {
      id: 'April',
      label: {
        long: 'April',
        short: 'Apr'
      },
      value: 4
    },
    MAI: {
      id: 'Mai',
      label: {
        long: 'Mai',
        short: 'Mai'
      },
      value: 5
    },
    JUNI: {
      id: 'Juni',
      label: {
        long: 'Juni',
        short: 'Jun'
      },
      value: 6
    },
    JULI: {
      id: 'Juli',
      label: {
        long: 'Juli',
        short: 'Jul'
      },
      value: 7
    },
    AUGUST: {
      id: 'August',
      label: {
        long: 'August',
        short: 'Aug'
      },
      value: 8
    },
    SEPTEMBER: {
      id: 'September',
      label: {
        long: 'September',
        short: 'Sep'
      },
      value: 9
    },
    OKTOBER: {
      id: 'Oktober',
      label: {
        long: 'Oktober',
        short: 'Okt'
      },
      value: 10
    },
    NOVEMBER: {
      id: 'November',
      label: {
        long: 'November',
        short: 'Nov'
      },
      value: 11
    },
    DEZEMBER: {
      id: 'Dezember',
      label: {
        long: 'Dezember',
        short: 'Dez'
      },
      value: 12
    }
  })
  .constant('PENDENZSTATUS', {
    AUSSTEHEND: 'Ausstehend',
    ERLEDIGT: 'Erledigt',
    NICHTERLEDIGT: 'NichtErledigt'
  })
  .run(function($rootScope, $location) {
    $rootScope.location = $location;
  })
  .factory('checkSize', ['$rootScope', '$window', function($rootScope, $window) {
    return function() {
      if ($window.innerWidth >= 1200) {
        $rootScope.tgState = true;
      }
    };
  }])
  .factory('exportTable', ['FileSaver', function(FileSaver) {
    return function(elementId, fileName) {
      var blob = new Blob([angular.element(elementId).html()], {
        type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'
      });
      FileSaver.saveAs(blob, fileName);
    };
  }])
  .factory('cloneObj', function() {
    var cloneObjFun = function(obj) {
      if (null === obj || 'object' !== typeof obj) {
        return obj;
      }
      var copy = obj.constructor();
      for (var attr in obj) {
        if (obj.hasOwnProperty(attr)) {
          copy[attr] = cloneObjFun(obj[attr]);
        }
      }
      return copy;
    };
    return cloneObjFun;
  })
  .factory('msgBus', ['$rootScope', function($rootScope) {
    var msgBus = {};
    msgBus.emitMsg = function(msg) {
      $rootScope.$emit(msg.type, msg);
    };
    msgBus.onMsg = function(msg, scope, func) {
      var unbind = $rootScope.$on(msg, func);
      scope.$on('$destroy', unbind);
    };
    return msgBus;
  }])
  .run(['ooClientMessageService', function(clientMessageService) {
    console.log('Start clientMessageService');
    clientMessageService.start();
  }])
  .config(['$httpProvider', function($httpProvider) {
    $httpProvider.defaults.transformResponse.push(function(responseData) {
      return convertDateStringsToDates(responseData);
    });
  }])
  .config(['$provide', function($provide) {
    $provide.decorator('$exceptionHandler', ['$log', '$injector',
      function(
        $log, $injector) {
        return function(exception) {
          // using the injector to retrieve scope and timeout, otherwise circular dependency
          var $rootScope = $injector.get('$rootScope');
          var alertService = $injector.get('alertService');

          $rootScope.$removeAlert = alertService.removeAlert();
          alertService.addAlert('error', exception.message);

          // log error default style
          $log.error.apply($log, arguments);
        };
      }
    ]);
  }])
  .filter('fromNow', function() {
    return function(input) {
      //TODO: replace with current locale
      moment.locale('de');
      return moment(input).fromNow();
    };
  })
  .config(function($routeProvider) {
    $routeProvider
      .when('/', {
        redirectTo: '/abos'
      })
      .when('/abotypen', {
        templateUrl: 'scripts/abotypen/overview/abotypenoverview.html',
        controller: 'AbotypenOverviewController',
        name: 'AbotypenOverview'
      })
      .when('/abotypen/new', {
        templateUrl: 'scripts/abotypen/detail/abotypendetail.html',
        controller: 'AbotypenDetailController',
        name: 'AbotypenDetail'
      })
      .when('/abotypen/:id', {
        templateUrl: 'scripts/abotypen/detail/abotypendetail.html',
        controller: 'AbotypenDetailController',
        name: 'AbotypenDetail'
      })
      .when('/kunden', {
        templateUrl: 'scripts/kunden/overview/kundenoverview.html',
        controller: 'KundenOverviewController',
        name: 'KundenOverview'
      })
      .when('/kunden/new', {
        templateUrl: 'scripts/kunden/detail/kundendetail.html',
        controller: 'KundenDetailController',
        name: 'KundeDetail'
      })
      .when('/kunden/:id', {
        templateUrl: 'scripts/kunden/detail/kundendetail.html',
        controller: 'KundenDetailController',
        name: 'KundeDetail'
      })
      .when('/kunden/:kundeId/abos/:id', {
        templateUrl: 'scripts/abos/detail/abosdetail.html',
        controller: 'AbosDetailController',
        name: 'AbosDetail'
      })
      .when('/produzenten', {
        templateUrl: 'scripts/produzenten/overview/produzentenoverview.html',
        controller: 'ProduzentenOverviewController',
        name: 'ProduzentenOverview'
      })
      .when('/produzenten/new', {
        templateUrl: 'scripts/produzenten/detail/produzentendetail.html',
        controller: 'ProduzentenDetailController',
        name: 'ProduzentenDetail'
      })
      .when('/produzenten/:id', {
        templateUrl: 'scripts/produzenten/detail/produzentendetail.html',
        controller: 'ProduzentenDetailController',
        name: 'ProduzentenDetail'
      })
      .when('/produzenten/:produzentId/abos/:id', {
        templateUrl: 'scripts/abos/detail/abosdetail.html',
        controller: 'AbosDetailController',
        name: 'AbosDetail'
      })
      .when('/produkte', {
        templateUrl: 'scripts/produkte/overview/produkteoverview.html',
        controller: 'ProdukteOverviewController',
        name: 'ProdukteOverview'
      })
      .when('/depots', {
        templateUrl: 'scripts/depots/overview/depotsoverview.html',
        controller: 'DepotsOverviewController',
        name: 'DepotsOverview'
      })
      .when('/depots/:id', {
        templateUrl: 'scripts/depots/detail/depotsdetail.html',
        controller: 'DepotsDetailController',
        name: 'DepotsDetail'
      })
      .when('/abos', {
        templateUrl: 'scripts/abos/overview/abosoverview.html',
        controller: 'AbosOverviewController',
        name: 'AbosOverview'
      })
      .when('/abos/:id', {
        templateUrl: 'scripts/abos/detail/abosdetail.html',
        controller: 'AbosDetailController',
        name: 'AbosDetail',
        resolve: {
          createKundeId: function() {
            return undefined;
          }
        }
      })
      .when('/touren', {
        templateUrl: 'scripts/touren/overview/tourenoverview.html',
        controller: 'TourenOverviewController',
        name: 'TourenOverview'
      })
      .when('/pendenzen', {
        templateUrl: 'scripts/pendenzen/overview/pendenzenoverview.html',
        controller: 'PendenzenOverviewController',
        name: 'PendenzenOverview'
      })
      .when('/korbplanung', {
        templateUrl: 'scripts/korbplanung/overview/korbplanungoverview.html',
        controller: 'KorbplanungOverviewController',
        name: 'KorbplanungDetail'
      })
      .when('/korbplanung/:id', {
        templateUrl: 'scripts/korbplanung/detail/korbplanungdetail.html',
        controller: 'KorbplanungDetailController',
        name: 'KorbplanungOverview'
      })
      .when('/settings', {
        templateUrl: 'scripts/projekt/settings/projektsettings.html',
        controller: 'ProjektSettingsController',
        name: 'ProjektSettings'
      })
      .otherwise({
        templateUrl: 'scripts/not-found.html'
      });
  });
<|endoftext|>


<commit_before>(function(document) {
  'use strict';

  var app = document.querySelector('#app');

  window.addEventListener('WebComponentsReady', function() {

    /**
     * The data to use.
     */
    app.automata = {values: []};

    app.liveCompiling = true;

    app.helpDialogSelectedTab = 0;

    /**
     * Compile the code in the text editor.
     * Create and display the new automata.
     */
    app.compile = function() {
      app.$.console.clear();
      app.$.console.log('Compiling...');
      var compileStartTime = (new Date()).getTime();
      var compileTime;

      setTimeout(function() {
        var code = app.$.editor.getCode();
        if (code.trim().length === 0) {
          app.$.console.clear();
          app.$.console.log('No input.');
          return;
        }

        var automata = [];
        try {
          automata = app.$.parser.parse(code);
        } catch (e) {
          var buildErrorMessage = function(e) {
            return e.location !== undefined ?
              'on line ' + e.location.start.line + ', col ' + e.location.start.column + ' - ' + e.message :
              e.message;
          };

          var isInterpreterException = e.constructor === app.$.parser.InterpreterException;
          var prefix = isInterpreterException ? 'Error: ' : 'Syntax error ';

          compileTime = Math.max(1, ((new Date()).getTime() - compileStartTime)) / 1000;
          app.$.console.clear(1);
          app.$.console.log('Compulation failed after ' + compileTime.toFixed(3) + ' seconds.');
          app.$.console.error(prefix + buildErrorMessage(e));
          return;
        }

        compileTime = Math.max(1, ((new Date()).getTime() - compileStartTime)) / 1000;
        app.$.console.clear(1);
        app.$.console.log('Compiled successfully in ' + compileTime.toFixed(3) + ' seconds.');
        app.$.console.log('Rendering...');

        var renderStartTime = (new Date()).getTime();
        var renderTime;

        // Can't simply assign app.automata.values to the new array as data bindings will not update.
        // Creating a new automata oject then setting the its values slightly later will work (for some reason).
        app.automata = {};
        setTimeout(function() {
          app.set('automata.values', automata);

          renderTime = Math.max(1, ((new Date()).getTime() - renderStartTime)) / 1000;
          app.$.console.clear(1);
          app.$.console.log('Rendered successfully in ' + renderTime.toFixed(3) + ' seconds.');
          app.$.console.log('Total time: ' + (compileTime + renderTime).toFixed(3) + ' seconds.');
        }, 0);
      }.bind(this), 0);
    };

    /**
     * Open a text file from the user's computer and use its contents as the code
     */
    app.openFile = function() {
      var opener = app.$['open-file'];
      opener.click();
      opener.onchange = function(e) {
        if (opener.value === '') {
          return;
        }
        var input = e.target;
        var reader = new FileReader();
        reader.onload = function() {
          var text = reader.result;
          app.$.editor.setCode(text, app.liveCompiling);
          app.$.editor.focus();
        };
        reader.readAsText(input.files[0]);
        opener.value = '';
      };
    };

    /**
     * Save to code the user has written to their computer (as a download).
     */
    app.downloadFile = function() {
      var blob = new Blob(
        [app.$.editor.getCode()],
        {type: 'text/plain;charset=utf-8'});
      saveAs(blob, 'untitled.txt');
    };

    app.showHelp = function() {
      var help = app.$['help-dialog'];
      help.open();
    };

    app.$['chbx-live-compiling'].addEventListener('iron-change', function() {
      if (app.liveCompiling) {
        app.compile();
      }
      app.$.editor.focus();
    });

    document.addEventListener('automata-walker-start', function(e) {
      var visualisations = Polymer.dom(this).querySelectorAll('automata-visualisation');
      for (var i in visualisations) {
        visualisations[i].setHighlightNodeId(e.detail.node);
        visualisations[i].redraw();
      }
    });

    document.addEventListener('automata-walker-walk', function(e) {
      var visualisations = Polymer.dom(this).querySelectorAll('automata-visualisation');
      for (var i in visualisations) {
        visualisations[i].setHighlightNodeId(e.detail.edge.to);
        visualisations[i].redraw();
      }
    });

    document.addEventListener('text-editor-change', function() {
      if (app.liveCompiling) {
        app.compile();
      }
    });

    /**
     * Listen for key presses.
     * Note: Needs to listen for keydown (not keyup) in order to prevent browser default action
     */
    document.addEventListener('keydown',function(e) {
      if (app.$['help-dialog'].opened) {
        return;
      }

      switch (e.keyCode) {
        case 13:
          // CTRL + ENTER
          if (e.ctrlKey) {
            app.compile();
            e.preventDefault();
          }
          break;
        case 79:
          // CTRL + O
          if (e.ctrlKey) {
            app.openFile();
            e.preventDefault();
          }
          break;
        case 83:
          // CTRL + S
          if (e.ctrlKey) {
            app.downloadFile();
            e.preventDefault();
          }
          break;
        case 112:
          // F1
          app.$['help-dialog'].open();
          e.preventDefault();
          break;
        default: return;
      }
    });

  });
})(document);
<commit_msg>added documentation to the app.js file<commit_after>(function(document) {
  'use strict';

  var app = document.querySelector('#app');

  window.addEventListener('WebComponentsReady', function() {

    /**
     * The data to use.
     */
    app.automata = {values: []};

    app.liveCompiling = true;

    app.helpDialogSelectedTab = 0;

    /**
     * Compile the code in the text editor.
     * Create and display the new automata.
     */
    app.compile = function() {
      app.$.console.clear();
      app.$.console.log('Compiling...');
      var compileStartTime = (new Date()).getTime();
      var compileTime;

      setTimeout(function() {
        var code = app.$.editor.getCode();
        if (code.trim().length === 0) {
          app.$.console.clear();
          app.$.console.log('No input.');
          return;
        }

        var automata = [];
        try {
          automata = app.$.parser.parse(code);
        } catch (e) {
          var buildErrorMessage = function(e) {
            return e.location !== undefined ?
              'on line ' + e.location.start.line + ', col ' + e.location.start.column + ' - ' + e.message :
              e.message;
          };

          var isInterpreterException = e.constructor === app.$.parser.InterpreterException;
          var prefix = isInterpreterException ? 'Error: ' : 'Syntax error ';

          compileTime = Math.max(1, ((new Date()).getTime() - compileStartTime)) / 1000;
          app.$.console.clear(1);
          app.$.console.log('Compulation failed after ' + compileTime.toFixed(3) + ' seconds.');
          app.$.console.error(prefix + buildErrorMessage(e));
          return;
        }

        compileTime = Math.max(1, ((new Date()).getTime() - compileStartTime)) / 1000;
        app.$.console.clear(1);
        app.$.console.log('Compiled successfully in ' + compileTime.toFixed(3) + ' seconds.');
        app.$.console.log('Rendering...');

        var renderStartTime = (new Date()).getTime();
        var renderTime;

        // Can't simply assign app.automata.values to the new array as data bindings will not update.
        // Creating a new automata oject then setting the its values slightly later will work (for some reason).
        app.automata = {};
        setTimeout(function() {
          app.set('automata.values', automata);

          renderTime = Math.max(1, ((new Date()).getTime() - renderStartTime)) / 1000;
          app.$.console.clear(1);
          app.$.console.log('Rendered successfully in ' + renderTime.toFixed(3) + ' seconds.');
          app.$.console.log('Total time: ' + (compileTime + renderTime).toFixed(3) + ' seconds.');
        }, 0);
      }.bind(this), 0);
    };

    /**
     * Open a text file from the user's computer and set the text-area to
     * the text parsed from the file.
     */
    app.openFile = function() {
      var opener = app.$['open-file'];
      opener.click();
      opener.onchange = function(e) {
        if (opener.value === '') {
          return;
        }
        var input = e.target;
        var reader = new FileReader();
        reader.onload = function() {
          var text = reader.result;
          app.$.editor.setCode(text, app.liveCompiling);
          app.$.editor.focus();
        };
        reader.readAsText(input.files[0]);
        opener.value = '';
      };
    };

    /**
     * Save to code the user has written to their computer (as a download).
     */
    app.downloadFile = function() {
      var blob = new Blob(
        [app.$.editor.getCode()],
        {type: 'text/plain;charset=utf-8'});
      saveAs(blob, 'untitled.txt');
    };

    /**
     * Opens the help-dialog.
     */
    app.showHelp = function() {
      var help = app.$['help-dialog'];
      help.open();
    };

    /**
     * Simple event listener for when the checkbox in ticked.
     * Compile is called if it is.
     */
    app.$['chbx-live-compiling'].addEventListener('iron-change', function() {
      if (app.liveCompiling) {
        app.compile();
      }
      app.$.editor.focus();
    });

    /**
     * This is the event which triggers when the user selects an automata from the
     * list to walk down. It sets the root node of this automata, and all automata
     * with this automata as a sub-graph, blue.
     */
    document.addEventListener('automata-walker-start', function(e) {
      var visualisations = Polymer.dom(this).querySelectorAll('automata-visualisation');
      for (var i in visualisations) {
        visualisations[i].setHighlightNodeId(e.detail.node);
        visualisations[i].redraw();
      }
    });
    /**
     * This is the event which triggers when the user presses the walk
     * button on the walker element. The walker has already checked for the valid
     * edge and thrown any errors. The edge to walk is given in the event argument
     * 'e.detail.edge'.
     */
    document.addEventListener('automata-walker-walk', function(e) {
      var visualisations = Polymer.dom(this).querySelectorAll('automata-visualisation');
      for (var i in visualisations) {
        visualisations[i].setHighlightNodeId(e.detail.edge.to);
        visualisations[i].redraw();
      }
    });

    /**
     * This is the event which triggers when the text in the text area is changed.
     * Only care about this if the live-compiling check-box is ticked.
     */
    document.addEventListener('text-editor-change', function() {
      if (app.liveCompiling) {
        app.compile();
      }
    });

    /**
     * Listen for key presses.
     * Note: Needs to listen for keydown (not keyup) in order to prevent browser default action
     */
    document.addEventListener('keydown',function(e) {
      if (app.$['help-dialog'].opened) {
        return;
      }

      switch (e.keyCode) {
        case 13:
          // CTRL + ENTER
          if (e.ctrlKey) {
            app.compile();
            e.preventDefault();
          }
          break;
        case 79:
          // CTRL + O
          if (e.ctrlKey) {
            app.openFile();
            e.preventDefault();
          }
          break;
        case 83:
          // CTRL + S
          if (e.ctrlKey) {
            app.downloadFile();
            e.preventDefault();
          }
          break;
        case 112:
          // F1
          app.$['help-dialog'].open();
          e.preventDefault();
          break;
        default: return;
      }
    });

  });
})(document);
<|endoftext|>