<commit_before>var app = require('app');  // Module to control application life.
process.env.directory = process.env.directory || app.getAppPath()
var BrowserWindow = require('browser-window');  // Module to create native browser window.

var http = require('http');
var fs = require('fs-extra');
var path = require('path');
var ipc = require('ipc');
var dialog = require('dialog');
var server = require('./server');
var dotenv = require('dotenv');

ipc.on('show_configuration', function(event, arg) {
  try{
    _defaults = getDefaultSettings()
    _results = {
      'directory': process.env.data_directory || _defaults.data_directory,
      'station': process.env.station || _defaults.station,
      'baseUrl': process.env.baseUrl,
      'shared_secret': process.env.shared_secret,
      'locale': process.env.locale || _defaults.locale,
      'community_lands': !(process.env.community_lands_server === undefined || process.env.community_lands_token === undefined)
    };
    console.log(_results);
    event.sender.send('has_configuration', _results);
  } catch (err) {
    event.sender.send('has_configuration', []);
  }
});

ipc.on('backup_submissions', function(event, arg) {
  var options = {
    hostname: 'localhost',
    port: process.env.port || 3000,
    path: '/save/all',
    method: 'GET'
  };
  var req = http.request(options, function(res) {
    var data = "";
    res.on('data', function(chunk) {
      data += chunk;
    });
    res.on('end', function() {
      event.sender.send('backup_submissions_complete', data);
    });
  }).on('error', function(e) {
    event.sender.send('backup_submissions_complete', '{"error":true, "code":"could_not_connect", "message":"Could not connect to server"}');
  }).end();
});

ipc.on('check_last_backup', function(event, arg) {
  var options = {
    hostname: 'localhost',
    port: process.env.port || 3000,
    path: '/save/status',
    method: 'GET'
  };
  var req = http.request(options, function(res) {
    var data = ""
    res.on('data', function(chunk) {
      data += chunk;
    });
    res.on('end', function() {
      event.sender.send('has_last_backup', data);
    });
  }).end();
});

ipc.on('form_delete', function(event, arg) {
  var folder = path.join(process.env.data_directory, 'Monitoring', process.env.station, 'Forms');
  fs.readdir(folder, function(err, files) {
    if (err) {
      event.sender.send('has_form_delete');
    } else {
      for (var i in files) {
        if (files[i] == arg) {
          fs.unlinkSync(path.join(folder, files[i]));
          event.sender.send('has_form_delete');
          break;
        }
      }
    }
  });
});

ipc.on('form_list', function(event, arg) {
  var folder = path.join(process.env.data_directory, 'Monitoring', process.env.station, 'Forms');
  fs.readdir(folder, function(err, files) {
    var data = { forms: [] };
    if (err)
      event.sender.send('has_form_list', data);
    else {
      data.forms = files;
      event.sender.send('has_form_list', data);
    }
  });
});

ipc.on('select_data_directory', function(event, arg) {
  var options = {
    properties: ['openDirectory'],
    defaultPath: process.env.data_directory
  };
  dialog.showOpenDialog(mainWindow, options, function(folder) {
    if (folder) {
      event.sender.send('has_select_data_directory', folder);
    }
  });
});

ipc.on('select_form', function(event, arg) {
  var options = {
    properties: ['openFile', 'multiSelections'],
    filters: [ { name: 'XML', extensions: ['xml'] } ]
  };
  dialog.showOpenDialog(mainWindow, options, function(arr) {
    if (arr !== undefined) {
      var destDir = path.join(process.env.data_directory, 'Monitoring', process.env.station, 'Forms');
      var uploaded = {
        count: arr.length,
        names: []
      };
      for (var index in arr) {
        var source = arr[index];
        var filename = path.basename(source);
        var target = path.join(destDir, filename);
        fs.copySync(source, target);
        uploaded.names.push(filename);
      }
      event.sender.send('has_select_form', uploaded);
    }
  });
});

ipc.on('filter_list', function(event, arg) {
  var options = {
    hostname: 'localhost',
    port: process.env.port || 3000,
    path: '/mapfilter/filters',
    method: 'GET'
  };
  var req = http.request(options, function(res) {
    var data = "";
    res.on('data', function(chunk) {
      data += chunk;
    });
    res.on('end', function() {
      event.sender.send('has_filter_list', data);
    });
  }).on('error', function(e) {
    event.sender.send('has_filter_list', '{"error":true, "code":"could_not_connect", "message":"Could not connect to server"}');
  }).end();
});

ipc.on('settings_list', function(event, arg) {
  fs.readFile(path.join(__dirname, '.env'), 'utf8', function(err, data) {
    if (err) {
      event.sender.send('has_settings_list', getDefaultSettings());
    } else {
      var defaults = getDefaultSettings();
      var selected = dotenv.parse(data);
      for (var key in selected)
        defaults[key] = selected[key];
      event.sender.send('has_settings_list', defaults);
    }
  });
});

ipc.on('settings_save', function(event, arg) {
  var properties = "";
  for (var key in arg) {
    if (arg[key]) {
      properties += key + '=' + arg[key];
      properties += "\r\n"
    }
  }
  fs.writeFile(path.join(__dirname, '.env'), properties, 'utf8', function(err) {
    if (err)
      event.sender.send('has_settings_save', '{"error",true, "code":"could_not_save_settings", "message":"Could not save settings file"}');
    else
      event.sender.send('has_settings_save', '{"error":false}');
  });
});

ipc.on('community_lands_backup', function(event, arg) {
  if (process.env.community_lands_server) {
    var options = {
      hostname: 'localhost',
      port: process.env.port || 3000,
      path: '/backup/latest',
      method: 'GET'
    };
    var req = http.request(options, function(res) {
      var data = "";
      res.on('data', function(chunk) {
        data += chunk;
      });
      res.on('end', function() {
        event.sender.send('has_community_lands_backup', data);
      });
    }).on('error', function(e) {
      event.sender.send('has_community_lands_backup', '{"error":true, "code":"could_not_connect", "message":"Could not connect to server"}');
    }).end();
  } else {
    event.sender.send('has_community_lands_backup', '{"error":true, "code":"community_lands_not_configured", "message":"Community Lands connection not configured"}');
  }
});

ipc.on('community_lands_status', function(event, arg) {
  if (process.env.community_lands_server) {
    var options = {
      hostname: 'localhost',
      port: process.env.port || 3000,
      path: '/backup/status',
      method: 'GET',
    };
    var req = http.request(options, function(res) {
      var data = "";
      res.on('data', function(chunk) {
        data += chunk;
      });
      res.on('end', function() {
        event.sender.send('has_community_lands_status', data);
      });
    }).on('error', function(e) {
      event.sender.send('has_community_lands_status', null);
    }).end();
  } else {
    event.sender.send('has_community_lands_status', null);
  }
});

ipc.on('community_lands_online', function(event, arg) {
  event.sender.send('has_community_lands_online', arg);
});

var FiltersDir = path.join(process.env.data_directory, 'Monitoring', process.env.station, 'Filters');
try {
  fs.mkdirpSync(FiltersDir);
} catch (e) { //It's ok
}
fs.watch(FiltersDir, function(evt, filename) {
  mainWindow.reload();
});

var getDefaultSettings = function() {
  return {
    data_directory: path.join(__dirname),
    station: 'DEMO',
    locale: 'en',
    community_lands_server: 'http://www.communitylands.org',
    community_lands_port: 80,
    community_lands_token: null,
    port: 3000,
    shared_secret: 'demo',
    mapZoom: null,
    mapCenterLat: null,
    mapCenterLong: null
  };
};

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
var mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  app.quit();
});

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on('ready', function() {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 400, height: 400});

  // and load the index.html of the app.
  mainWindow.loadUrl('file://' + __dirname + '/index.html?locale=' + (process.env.locale || 'en'));

  // Open the DevTools.
  // mainWindow.openDevTools();

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
});
<commit_msg>Lint main.js<commit_after>var app = require('app') // Module to control application life.
process.env.directory = process.env.directory || app.getAppPath()
var BrowserWindow = require('browser-window') // Module to create native browser window.

var http = require('http')
var fs = require('fs-extra')
var path = require('path')
var ipc = require('ipc')
var dialog = require('dialog')
var dotenv = require('dotenv')

ipc.on('show_configuration', function (event, arg) {
  try {
    var _defaults = getDefaultSettings()
    var _results = {
      'directory': process.env.data_directory || _defaults.data_directory,
      'station': process.env.station || _defaults.station,
      'baseUrl': process.env.baseUrl,
      'shared_secret': process.env.shared_secret,
      'locale': process.env.locale || _defaults.locale,
      'community_lands': !(process.env.community_lands_server === undefined || process.env.community_lands_token === undefined)
    }
    console.log(_results)
    event.sender.send('has_configuration', _results)
  } catch (err) {
    event.sender.send('has_configuration', [])
  }
})

ipc.on('backup_submissions', function (event, arg) {
  var options = {
    hostname: 'localhost',
    port: process.env.port || 3000,
    path: '/save/all',
    method: 'GET'
  }
  http.request(options, function (res) {
    var data = ''
    res.on('data', function (chunk) {
      data += chunk
    })
    res.on('end', function () {
      event.sender.send('backup_submissions_complete', data)
    })
  }).on('error', function (e) {
    event.sender.send('backup_submissions_complete', '{"error":true, "code":"could_not_connect", "message":"Could not connect to server"}')
  }).end()
})

ipc.on('check_last_backup', function (event, arg) {
  var options = {
    hostname: 'localhost',
    port: process.env.port || 3000,
    path: '/save/status',
    method: 'GET'
  }
  http.request(options, function (res) {
    var data = ''
    res.on('data', function (chunk) {
      data += chunk
    })
    res.on('end', function () {
      event.sender.send('has_last_backup', data)
    })
  }).end()
})

ipc.on('form_delete', function (event, arg) {
  var folder = path.join(process.env.data_directory, 'Monitoring', process.env.station, 'Forms')
  fs.readdir(folder, function (err, files) {
    if (err) {
      event.sender.send('has_form_delete')
    } else {
      for (var i in files) {
        if (files[i] === arg) {
          fs.unlinkSync(path.join(folder, files[i]))
          event.sender.send('has_form_delete')
          break
        }
      }
    }
  })
})

ipc.on('form_list', function (event, arg) {
  var folder = path.join(process.env.data_directory, 'Monitoring', process.env.station, 'Forms')
  fs.readdir(folder, function (err, files) {
    var data = { forms: [] }
    if (err) {
      event.sender.send('has_form_list', data)
    } else {
      data.forms = files
      event.sender.send('has_form_list', data)
    }
  })
})

ipc.on('select_data_directory', function (event, arg) {
  var options = {
    properties: ['openDirectory'],
    defaultPath: process.env.data_directory
  }
  dialog.showOpenDialog(mainWindow, options, function (folder) {
    if (folder) {
      event.sender.send('has_select_data_directory', folder)
    }
  })
})

ipc.on('select_form', function (event, arg) {
  var options = {
    properties: ['openFile', 'multiSelections'],
    filters: [ { name: 'XML', extensions: ['xml'] } ]
  }
  dialog.showOpenDialog(mainWindow, options, function (arr) {
    if (arr !== undefined) {
      var destDir = path.join(process.env.data_directory, 'Monitoring', process.env.station, 'Forms')
      var uploaded = {
        count: arr.length,
        names: []
      }
      for (var index in arr) {
        var source = arr[index]
        var filename = path.basename(source)
        var target = path.join(destDir, filename)
        fs.copySync(source, target)
        uploaded.names.push(filename)
      }
      event.sender.send('has_select_form', uploaded)
    }
  })
})

ipc.on('filter_list', function (event, arg) {
  var options = {
    hostname: 'localhost',
    port: process.env.port || 3000,
    path: '/mapfilter/filters',
    method: 'GET'
  }
  http.request(options, function (res) {
    var data = ''
    res.on('data', function (chunk) {
      data += chunk
    })
    res.on('end', function () {
      event.sender.send('has_filter_list', data)
    })
  }).on('error', function (e) {
    event.sender.send('has_filter_list', '{"error":true, "code":"could_not_connect", "message":"Could not connect to server"}')
  }).end()
})

ipc.on('settings_list', function (event, arg) {
  fs.readFile(path.join(__dirname, '.env'), 'utf8', function (err, data) {
    if (err) {
      event.sender.send('has_settings_list', getDefaultSettings())
    } else {
      var defaults = getDefaultSettings()
      var selected = dotenv.parse(data)
      for (var key in selected)
        defaults[key] = selected[key]
      event.sender.send('has_settings_list', defaults)
    }
  })
})

ipc.on('settings_save', function (event, arg) {
  var properties = ''
  for (var key in arg) {
    if (arg[key]) {
      properties += key + '=' + arg[key]
      properties += '\r\n'
    }
  }
  fs.writeFile(path.join(__dirname, '.env'), properties, 'utf8', function (err) {
    if (err) {
      event.sender.send('has_settings_save', '{"error",true, "code":"could_not_save_settings", "message":"Could not save settings file"}')
    } else {
      event.sender.send('has_settings_save', '{"error":false}')
    }
  })
})

ipc.on('community_lands_backup', function (event, arg) {
  if (process.env.community_lands_server) {
    var options = {
      hostname: 'localhost',
      port: process.env.port || 3000,
      path: '/backup/latest',
      method: 'GET'
    }
    http.request(options, function (res) {
      var data = ''
      res.on('data', function (chunk) {
        data += chunk
      })
      res.on('end', function () {
        event.sender.send('has_community_lands_backup', data)
      })
    }).on('error', function (e) {
      event.sender.send('has_community_lands_backup', '{"error":true, "code":"could_not_connect", "message":"Could not connect to server"}')
    }).end()
  } else {
    event.sender.send('has_community_lands_backup', '{"error":true, "code":"community_lands_not_configured", "message":"Community Lands connection not configured"}')
  }
})

ipc.on('community_lands_status', function (event, arg) {
  if (process.env.community_lands_server) {
    var options = {
      hostname: 'localhost',
      port: process.env.port || 3000,
      path: '/backup/status',
      method: 'GET'
    }
    http.request(options, function (res) {
      var data = ''
      res.on('data', function (chunk) {
        data += chunk
      })
      res.on('end', function () {
        event.sender.send('has_community_lands_status', data)
      })
    }).on('error', function (e) {
      event.sender.send('has_community_lands_status', null)
    }).end()
  } else {
    event.sender.send('has_community_lands_status', null)
  }
})

ipc.on('community_lands_online', function (event, arg) {
  event.sender.send('has_community_lands_online', arg)
})

var FiltersDir = path.join(process.env.data_directory, 'Monitoring', process.env.station, 'Filters')
try {
  fs.mkdirpSync(FiltersDir)
} catch (e) { // It's ok
}
fs.watch(FiltersDir, function (evt, filename) {
  mainWindow.reload()
})

var getDefaultSettings = function () {
  return {
    data_directory: path.join(__dirname),
    station: 'DEMO',
    locale: 'en',
    community_lands_server: 'http://www.communitylands.org',
    community_lands_port: 80,
    community_lands_token: null,
    port: 3000,
    shared_secret: 'demo',
    mapZoom: null,
    mapCenterLat: null,
    mapCenterLong: null
  }
}

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
var mainWindow = null

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  app.quit()
})

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
app.on('ready', function () {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 400, height: 400})

  // and load the index.html of the app.
  mainWindow.loadUrl('file://' + __dirname + '/index.html?locale=' + (process.env.locale || 'en'))

  // Open the DevTools.
  // mainWindow.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })
})
<|endoftext|>


<commit_before>import cx from 'classnames'
import DatePicker from 'react-datepicker'
import moment from 'moment'
import 'react-datepicker/dist/react-datepicker.css'

function getDate(date) {
  return date.add(date.utcOffset(), 'm').toISOString().split('T')[0]
}

export default ({ className, errors, onCommit, property, value }) => (

    <DatePicker
      className={cx(className, 'ct-input', 'ct-date-picker')}
      disabled={property.disabled}
      id={property.name}
      onChange={date => onCommit(getDate(date))}
      selected={value ? moment(value) : value}
      title={property.title} />

)
<commit_msg>fix: Handle null and partial dates in date-picker<commit_after>import cx from 'classnames'
import DatePicker from 'react-datepicker'
import moment from 'moment'
import 'react-datepicker/dist/react-datepicker.css'

function getDate(date) {
  return date && date.add(date.utcOffset(), 'm').toISOString().split('T')[0]
}

export default ({ className, errors, onCommit, property, value }) => (

    <DatePicker
      className={cx(className, 'ct-input', 'ct-date-picker')}
      disabled={property.disabled}
      id={property.name}
      onChange={date => onCommit(getDate(date))}
      selected={value ? moment(value) : value}
      title={property.title} />

)
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import UserLinks from './UserLinks';

export default class Nav extends Component {
  constructor() {
    super()

    this.state = {
      jokeNotebook: [
        'Chris Will Have The Meatloaf',
        '#SheepLife',
        'At Least Get Out Of Bed Today',
        'Don\'t worry, we\'ll handle it',
        'Choose not, want not',
        'Food > Choices',
        'Choice Not Included',
        'We choose, you eat',
        'Choose a nothing.',
        'Choice Not Included',
        'We pick so you don\'t have to!',
        'Choice is for bots',
        'Don\'t think. Eat.',
        'Free will, Schmee Will',
        'Single Option dining',
        'Free will is not a choice.',
        'CHOICE IS WASTED ON YOU.'
      ],
      tagline: ''
    }
  }

  componentDidMount() {
    const randomIndex = Math.floor(Math.random() * this.state.jokeNotebook.length);
    this.setState({ tagline: this.state.jokeNotebook[randomIndex]});
  }

  render() {
    return(

DECIDR

{this.state.tagline}

            <UserLinks />

    )
  }

}
<commit_msg>fix for merge<commit_after>import React, { Component } from 'react';
import UserLinks from './UserLinks';

export default class Nav extends Component {
  constructor() {
    super()

    this.state = {
      jokeNotebook: [
        'Chris Will Have The Meatloaf',
        '#SheepLife',
        'At Least Get Out Of Bed Today',
        'Don\'t worry, we\'ll handle it',
        'Choose not, want not',
        'Food > Choices',
        'Choice Not Included',
        'We choose, you eat',
        'Choose a nothing.',
        'Choice Not Included',
        'We pick so you don\'t have to!',
        'Choice is for bots',
        'Don\'t think. Eat.',
        'Free will, Schmee Will',
        'Single Option dining',
        'Free will is not a choice.',
        'CHOICE IS WASTED ON YOU.',
        'Debate ends',
        'There can be only one'
      ],
      tagline: ''
    }
  }

  componentDidMount() {
    const randomIndex = Math.floor(Math.random() * this.state.jokeNotebook.length);
    this.setState({ tagline: this.state.jokeNotebook[randomIndex]});
  }

  render() {
    return(

DECIDR

{this.state.tagline}

            <UserLinks />

    )
  }

}
<|endoftext|>


<commit_before>var socket = io.connect('http://' + window.location.host);
var accounts = [];
var filter = ""
var sortby = "time" //valid values: time abc zyx

function showUser(userData){
	var account = $('
').addClass("account col-md-2 panel panel-default");
	if(userData.credit < 0){
		account.addClass("debt");
	}
	account.append($('
').addClass("name").text(userData.name));
	account.append($('
').addClass("credit").text(userData.credit.toFixed(2) + " €"));

	$('#accounts').append(account);
	account.click(function(){
		showDetail(userData);
	})
}

function showDetail(userData){
	var detail = $('
');

	var row = $('
');
	detail.append(row);

	var userinfo = $('
');
	row.append(userinfo);

	userinfo.append($('
').addClass("name").text(userData.name));
	userinfo.append($('
').addClass("credit").text(userData.credit.toFixed(2) + " €"));

	// Add Credit-Area
	var addCreditArea = $('
').addClass('panel panel-default');
	addCreditArea.append($('
').addClass('panel-heading')
		.append($('
').addClass('panel-title').text('Add Credit'))
	);

	var creditarea = $('
');
	row.append(creditarea);

	creditarea.append(addCreditArea);
	var addCreditAreaBody = $('
').addClass('panel-body');
	addCreditArea.append(addCreditAreaBody);

	var plus50Button = $('<button>').addClass('btn btn-success btn-lg').text("+ 0.50€");
	var plus100Button = $('<button>').addClass('btn btn-success btn-lg').text("+ 1,00€");
	var plus200Button = $('<button>').addClass('btn btn-success btn-lg').text("+ 2,00€");
	var plus500Button = $('<button>').addClass('btn btn-success btn-lg').text("+ 5,00€");

	var plusbuttons = [plus50Button, plus100Button, plus200Button, plus500Button];
	addCreditAreaBody.append(plusbuttons);

	var removeCreditArea = $('
').addClass('panel panel-default');
	addCreditArea.append($('
').addClass('panel-heading')
		.append($('
').addClass('panel-title').text('Remove Credit'))
	);
	var removeCreditAreaBody = $('
').addClass('panel-body');

	addCreditArea.append(removeCreditAreaBody);

	var minus50Button  = $('<button>').addClass('btn btn-danger btn-lg').text("- 0,50€");
	var minus100Button = $('<button>').addClass('btn btn-danger btn-lg').text("- 1,00€");
	var minus150Button = $('<button>').addClass('btn btn-danger btn-lg').text("- 1,50€");
	var minus200Button = $('<button>').addClass('btn btn-danger btn-lg').text("- 2,00€");

	var minusbuttons = [minus50Button, minus100Button, minus150Button, minus200Button]
	removeCreditAreaBody.append(minusbuttons);

	var renameButton = $('
').addClass('pager').append($('
').addClass('previous').append($('').text('rename')));
	detail.append(renameButton);

	var backButton = $('
').addClass('pager').append($('
').addClass('previous').append($('').text('← Back')));
	detail.append(backButton);

	$('#details').empty().append(detail);
	changeView('details');

	// Plus Buttons
	plus50Button.click(function(){
		changeCredit(userData, 0.5);
	});
	plus100Button.click(function(){
		changeCredit(userData, 1);
	});
	plus200Button.click(function(){
		changeCredit(userData, 2);
	});
	plus500Button.click(function(){
		changeCredit(userData, 5);
	});

	// Minus Buttons
	minus50Button.click(function(){
		changeCredit(userData, -0.5);
	});
	minus100Button.click(function(){
		changeCredit(userData, -1);
	});
	minus150Button.click(function(){
		changeCredit(userData, -1.5);
	});
	minus200Button.click(function(){
		changeCredit(userData, -2);
	});

	// Back Button
	backButton.click(function(){
		changeView('accounts');
	});

	// rename Button
	renameButton.click(function(){
		renameUser(userData);
	});
}

function showStatistics(){
	$('#statistics').empty();
	var saldo = 0;
	accounts.forEach(function(account){
		saldo += account.credit;
	});
	var statistic = $('
').addClass("statistic col-md-2 panel panel-default");
	statistic.append($('
').addClass("title").text("Gesamtsaldo"));
	statistic.append($('
').addClass("value").text(saldo + " €"));

	$('#statistics').append(statistic);

	var backButton = $('
').addClass('pager').append($('
').addClass('previous').append($('').text('← Back')));
	$('#statistics').append(backButton);

	backButton.click(function(){
		changeView('accounts');
	});
}

function getAllUsers(){
	$('#accounts').empty();

	accounts.sort(function (a, b) {
		switch(sortby){
			case "time":
				var aDate = new Date(a.lastchanged)
				var bDate = new Date(b.lastchanged)
				return (aDate < bDate) ? 1 : -1;
			case "abc":
				return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
			case "zyx":
				return b.name.toLowerCase().localeCompare(a.name.toLowerCase());
			default:
				throw "Invalid sorting criteria"
		}

	});

	var filtered = accounts.filter(function(account){
		return account.name.toLowerCase().indexOf(filter)!=-1
	});

	filtered.forEach(function(user){
		showUser(user);
	});
	var newuser = $('
').addClass('account col-md-2 panel panel-default')
		.append($('
').addClass('newuser').text('+'));
	$('#accounts').append(newuser);

	newuser.click(function(){
		newUser();
	});
}

function newUser(){
	$('#newuser').empty();
	var newUserForm = $('<form role="form" id="newUserForm">');
	var newUserFormGroup = $('
');
	newUserForm.append(newUserFormGroup);
	newUserFormGroup.append($('<input type="username" name="username" placeholder="user name   (15 characters maximum)" maxlength=15 required class="form-control">'));
	newUserFormGroup.append($('<input type="submit" value="Add user" class="form-control">'));

	var backButton = $('
').addClass('pager').append($('
').addClass('previous').append($('').text('← Back')));
	$('#newuser').append(backButton);

	newUserForm.submit(function(e){
		lockUi()
	    e.preventDefault();
	    $.ajax({
            url: '/user/add',
            type: "POST",
            data: $('#newUserForm').serialize(),
            success: function(){
            	releaseUi()
            	changeView('accounts');
            },
            error: function(err){
            	releaseUi()
            	alert(err.responseText);
            }
        });
	});

	backButton.click(function(){
		changeView('accounts');
	});

	$('#newuser').append(newUserForm);

	changeView('newuser');
}

function renameUser(userData){
	$('#renameuser').empty();
	var renameUserForm = $('<form role="form" id="renameUserForm">');
	var renameUserFormGroup = $('
');
	renameUserForm.append(renameUserFormGroup);
	renameUserFormGroup.append($('<input type="hidden" name="username" value="'+userData.name+'" required class="form-control">'));
	renameUserFormGroup.append($('<input type="username" name="newname" id="newname" placeholder="new name   (15 characters maximum)" maxlength=15 required class="form-control" >'));
	renameUserFormGroup.append($('<input type="submit" value="rename user" class="form-control">'));

	var backButton = $('
').addClass('pager').append($('
').addClass('previous').append($('').text('← Back')));
	$('#renameuser').append(backButton);

	renameUserForm.submit(function(e){
		lockUi()
	    e.preventDefault();
	    $.ajax({
            url: '/user/rename',
            type: "POST",
            data: $('#renameUserForm').serialize(),
            success: function(){
            	userData.name = $('#newname').val();
	            showDetail(userData);
            	releaseUi()
            	changeView('details');
            },
            error: function(err){
            	releaseUi()
            	alert(err.responseText);
            }
        });
	});

	backButton.click(function(){
		changeView('details');
	});

	$('#renameuser').append(renameUserForm);

	changeView('rename');
}

var timer = null;

function changeView(view){
   resetTimer();
	$('.view').hide();
	switch(view){
		case 'details':
			$('#details').show();
			break;
		case 'accounts':
			socket.emit('getAccounts');
			$('#accounts').show();
			$("nav").show();
			break;
		case 'newuser':
			$('#newuser').show();
			break;
		case 'rename':
			$('#renameuser').show();
			break;
		case 'statistics':
			socket.emit('getAccounts');
			showStatistics();
			$('#statistics').show();
			break;

		default:
			throw 'Invalid View: ' + view;
	}
}

function resetTimer(){
    if (timer !== null)
        clearTimeout(timer);
    timer = setTimeout(function() {
//        changeView('accounts');
        timer = null;
    }, 23.42 * 1000);
}

function changeCredit(userData, delta){
	lockUi()
	$.ajax({
		url: "/user/credit",
		type: "POST",
		dataType: "json",
		data: {
			"username": userData.name,
			"delta": delta
		}
	}).done(function(data){
		showDetail(data);
		releaseUi()
	});
}

function lockUi(){
	$("#uilock").modal({
		backdrop: false,
		keyboard: false,

	})
}

function releaseUi(){
	$("#uilock").modal('hide')
}

socket.on('accounts', function (data) {
	var data = JSON.parse(data);
	accounts = data;
	getAllUsers();
});

socket.on('ka-ching', function() {
    var p = $('#ka-ching').get(0);
    p.pause();
    p.currentTime = 0;
    p.play();
});

socket.on('one-up', function() {
    var p = $('#one-up').get(0);
    p.pause();
    p.currentTime = 0;
    p.play();
});

function updateFilter(){
	filter = $("#search input").get(0).value.toLowerCase()
	changeView("accounts")
}

function setup(){
	$("#search input").on("input", null, null, updateFilter)
	$("#search button").click(function(e){
		//fix because click fires before the field is actually reseted
		e.preventDefault();
		$("#search").get(0).reset();
		updateFilter();
	})
	$("#searchtoggle").click(function(){
		if($("#search").is(":visible")){
			$("#search").get(0).reset();
			updateFilter();
			$("#searchtoggle").removeClass("active");
			$("#search").hide();
		}else{
			$("#searchtoggle").addClass("active");
			$("#search").show();
		}
	})
	$("#search").hide();

	$("#stats").click(function(){changeView('statistics')});
	$("#sorttime").click(function(){setSort("time")});
	$("#sortabc").click(function(){setSort("abc")});
	$("#sortzyx").click(function(){setSort("zyx")});
}

function setSort(by){
	sortby = by;
	changeView("accounts");
	$(".sortbtn").removeClass("active");
	$("#sort"+by).addClass("active");
}

setup();
changeView('accounts');
<commit_msg>re-introducing the timeout to jump back to the main page<commit_after>var socket = io.connect('http://' + window.location.host);
var accounts = [];
var filter = ""
var sortby = "time" //valid values: time abc zyx

function showUser(userData){
	var account = $('
').addClass("account col-md-2 panel panel-default");
	if(userData.credit < 0){
		account.addClass("debt");
	}
	account.append($('
').addClass("name").text(userData.name));
	account.append($('
').addClass("credit").text(userData.credit.toFixed(2) + " €"));

	$('#accounts').append(account);
	account.click(function(){
		showDetail(userData);
	})
}

function showDetail(userData){
	var detail = $('
');

	var row = $('
');
	detail.append(row);

	var userinfo = $('
');
	row.append(userinfo);

	userinfo.append($('
').addClass("name").text(userData.name));
	userinfo.append($('
').addClass("credit").text(userData.credit.toFixed(2) + " €"));

	// Add Credit-Area
	var addCreditArea = $('
').addClass('panel panel-default');
	addCreditArea.append($('
').addClass('panel-heading')
		.append($('
').addClass('panel-title').text('Add Credit'))
	);

	var creditarea = $('
');
	row.append(creditarea);

	creditarea.append(addCreditArea);
	var addCreditAreaBody = $('
').addClass('panel-body');
	addCreditArea.append(addCreditAreaBody);

	var plus50Button = $('<button>').addClass('btn btn-success btn-lg').text("+ 0.50€");
	var plus100Button = $('<button>').addClass('btn btn-success btn-lg').text("+ 1,00€");
	var plus200Button = $('<button>').addClass('btn btn-success btn-lg').text("+ 2,00€");
	var plus500Button = $('<button>').addClass('btn btn-success btn-lg').text("+ 5,00€");

	var plusbuttons = [plus50Button, plus100Button, plus200Button, plus500Button];
	addCreditAreaBody.append(plusbuttons);

	var removeCreditArea = $('
').addClass('panel panel-default');
	addCreditArea.append($('
').addClass('panel-heading')
		.append($('
').addClass('panel-title').text('Remove Credit'))
	);
	var removeCreditAreaBody = $('
').addClass('panel-body');

	addCreditArea.append(removeCreditAreaBody);

	var minus50Button  = $('<button>').addClass('btn btn-danger btn-lg').text("- 0,50€");
	var minus100Button = $('<button>').addClass('btn btn-danger btn-lg').text("- 1,00€");
	var minus150Button = $('<button>').addClass('btn btn-danger btn-lg').text("- 1,50€");
	var minus200Button = $('<button>').addClass('btn btn-danger btn-lg').text("- 2,00€");

	var minusbuttons = [minus50Button, minus100Button, minus150Button, minus200Button]
	removeCreditAreaBody.append(minusbuttons);

	var renameButton = $('
').addClass('pager').append($('
').addClass('previous').append($('').text('rename')));
	detail.append(renameButton);

	var backButton = $('
').addClass('pager').append($('
').addClass('previous').append($('').text('← Back')));
	detail.append(backButton);

	$('#details').empty().append(detail);
	changeView('details');

	// Plus Buttons
	plus50Button.click(function(){
		changeCredit(userData, 0.5);
	});
	plus100Button.click(function(){
		changeCredit(userData, 1);
	});
	plus200Button.click(function(){
		changeCredit(userData, 2);
	});
	plus500Button.click(function(){
		changeCredit(userData, 5);
	});

	// Minus Buttons
	minus50Button.click(function(){
		changeCredit(userData, -0.5);
	});
	minus100Button.click(function(){
		changeCredit(userData, -1);
	});
	minus150Button.click(function(){
		changeCredit(userData, -1.5);
	});
	minus200Button.click(function(){
		changeCredit(userData, -2);
	});

	// Back Button
	backButton.click(function(){
		changeView('accounts');
	});

	// rename Button
	renameButton.click(function(){
		renameUser(userData);
	});
}

function showStatistics(){
	$('#statistics').empty();
	var saldo = 0;
	accounts.forEach(function(account){
		saldo += account.credit;
	});
	var statistic = $('
').addClass("statistic col-md-2 panel panel-default");
	statistic.append($('
').addClass("title").text("Gesamtsaldo"));
	statistic.append($('
').addClass("value").text(saldo + " €"));

	$('#statistics').append(statistic);

	var backButton = $('
').addClass('pager').append($('
').addClass('previous').append($('').text('← Back')));
	$('#statistics').append(backButton);

	backButton.click(function(){
		changeView('accounts');
	});
}

function getAllUsers(){
	$('#accounts').empty();

	accounts.sort(function (a, b) {
		switch(sortby){
			case "time":
				var aDate = new Date(a.lastchanged)
				var bDate = new Date(b.lastchanged)
				return (aDate < bDate) ? 1 : -1;
			case "abc":
				return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
			case "zyx":
				return b.name.toLowerCase().localeCompare(a.name.toLowerCase());
			default:
				throw "Invalid sorting criteria"
		}

	});

	var filtered = accounts.filter(function(account){
		return account.name.toLowerCase().indexOf(filter)!=-1
	});

	filtered.forEach(function(user){
		showUser(user);
	});
	var newuser = $('
').addClass('account col-md-2 panel panel-default')
		.append($('
').addClass('newuser').text('+'));
	$('#accounts').append(newuser);

	newuser.click(function(){
		newUser();
	});
}

function newUser(){
	$('#newuser').empty();
	var newUserForm = $('<form role="form" id="newUserForm">');
	var newUserFormGroup = $('
');
	newUserForm.append(newUserFormGroup);
	newUserFormGroup.append($('<input type="username" name="username" placeholder="user name   (15 characters maximum)" maxlength=15 required class="form-control">'));
	newUserFormGroup.append($('<input type="submit" value="Add user" class="form-control">'));

	var backButton = $('
').addClass('pager').append($('
').addClass('previous').append($('').text('← Back')));
	$('#newuser').append(backButton);

	newUserForm.submit(function(e){
		lockUi()
	    e.preventDefault();
	    $.ajax({
            url: '/user/add',
            type: "POST",
            data: $('#newUserForm').serialize(),
            success: function(){
            	releaseUi()
            	changeView('accounts');
            },
            error: function(err){
            	releaseUi()
            	alert(err.responseText);
            }
        });
	});

	backButton.click(function(){
		changeView('accounts');
	});

	$('#newuser').append(newUserForm);

	changeView('newuser');
}

function renameUser(userData){
	$('#renameuser').empty();
	var renameUserForm = $('<form role="form" id="renameUserForm">');
	var renameUserFormGroup = $('
');
	renameUserForm.append(renameUserFormGroup);
	renameUserFormGroup.append($('<input type="hidden" name="username" value="'+userData.name+'" required class="form-control">'));
	renameUserFormGroup.append($('<input type="username" name="newname" id="newname" placeholder="new name   (15 characters maximum)" maxlength=15 required class="form-control" >'));
	renameUserFormGroup.append($('<input type="submit" value="rename user" class="form-control">'));

	var backButton = $('
').addClass('pager').append($('
').addClass('previous').append($('').text('← Back')));
	$('#renameuser').append(backButton);

	renameUserForm.submit(function(e){
		lockUi()
	    e.preventDefault();
	    $.ajax({
            url: '/user/rename',
            type: "POST",
            data: $('#renameUserForm').serialize(),
            success: function(){
            	userData.name = $('#newname').val();
	            showDetail(userData);
            	releaseUi()
            	changeView('details');
            },
            error: function(err){
            	releaseUi()
            	alert(err.responseText);
            }
        });
	});

	backButton.click(function(){
		changeView('details');
	});

	$('#renameuser').append(renameUserForm);

	changeView('rename');
}

var timer = null;

function changeView(view){
   resetTimer();
	$('.view').hide();
	switch(view){
		case 'details':
			$('#details').show();
			break;
		case 'accounts':
			socket.emit('getAccounts');
			$('#accounts').show();
			$("nav").show();
			break;
		case 'newuser':
			$('#newuser').show();
			break;
		case 'rename':
			$('#renameuser').show();
			break;
		case 'statistics':
			socket.emit('getAccounts');
			showStatistics();
			$('#statistics').show();
			break;

		default:
			throw 'Invalid View: ' + view;
	}
}

function resetTimer(){
    if (timer !== null)
        clearTimeout(timer);
    timer = setTimeout(function() {
        changeView('accounts');
        timer = null;
    }, 23.42 * 1000);
}

function changeCredit(userData, delta){
	lockUi()
	$.ajax({
		url: "/user/credit",
		type: "POST",
		dataType: "json",
		data: {
			"username": userData.name,
			"delta": delta
		}
	}).done(function(data){
		showDetail(data);
		releaseUi()
	});
}

function lockUi(){
	$("#uilock").modal({
		backdrop: false,
		keyboard: false,

	})
}

function releaseUi(){
	$("#uilock").modal('hide')
}

socket.on('accounts', function (data) {
	var data = JSON.parse(data);
	accounts = data;
	getAllUsers();
});

socket.on('ka-ching', function() {
    var p = $('#ka-ching').get(0);
    p.pause();
    p.currentTime = 0;
    p.play();
});

socket.on('one-up', function() {
    var p = $('#one-up').get(0);
    p.pause();
    p.currentTime = 0;
    p.play();
});

function updateFilter(){
	filter = $("#search input").get(0).value.toLowerCase()
	changeView("accounts")
}

function setup(){
	$("#search input").on("input", null, null, updateFilter)
	$("#search button").click(function(e){
		//fix because click fires before the field is actually reseted
		e.preventDefault();
		$("#search").get(0).reset();
		updateFilter();
	})
	$("#searchtoggle").click(function(){
		if($("#search").is(":visible")){
			$("#search").get(0).reset();
			updateFilter();
			$("#searchtoggle").removeClass("active");
			$("#search").hide();
		}else{
			$("#searchtoggle").addClass("active");
			$("#search").show();
		}
	})
	$("#search").hide();

	$("#stats").click(function(){changeView('statistics')});
	$("#sorttime").click(function(){setSort("time")});
	$("#sortabc").click(function(){setSort("abc")});
	$("#sortzyx").click(function(){setSort("zyx")});
}

function setSort(by){
	sortby = by;
	changeView("accounts");
	$(".sortbtn").removeClass("active");
	$("#sort"+by).addClass("active");
}

setup();
changeView('accounts');
<|endoftext|>


<commit_before>const _             = require('lodash');
const Promise       = require('bluebird');
const elasticsearch = require('elasticsearch');
const sr            = require('sync-request');
const bunyan        = require('bunyan');
const PrettyStream  = require('bunyan-prettystream');
const semver        = require('semver');
const config        = require('../config');

const prettyStdOut = new PrettyStream({mode: 'dev'});
prettyStdOut.pipe(process.stdout);

const LogToBunyan = function () {
  const self = this;
  const bun  = bunyan.createLogger({
    name:   `${config.FRAMEWORK_NAME}-es`,
    type:   'raw',
    level:  config.elasticsearch.logLevel,
    stream: prettyStdOut
  });

  self.error = bun.error.bind(bun);
  self.warning = bun.warn.bind(bun);
  self.info = bun.info.bind(bun);
  self.debug = bun.debug.bind(bun);
  self.trace = (method, requestUrl, body, responseBody, responseStatus) => {
    bun.trace({
      method:         method,
      requestUrl:     requestUrl,
      body:           body,
      responseBody:   responseBody,
      responseStatus: responseStatus
    });
  };
  self.close = () => {
  };
};

const DEFAULT_ELASTICSEARCH_PORT = 9200;
const SUPPORTED_API_VERSION      = _.keys(elasticsearch.Client.apis);

const createEsClient = (hostConfig) => {
  const host = hostConfig.host || 'localhost';
  const port = hostConfig.port || DEFAULT_ELASTICSEARCH_PORT;

  let path = hostConfig.path || '/';
  if (!path.startsWith('/')) {
    path = `/${path}`;
  }

  let uri = `${host}:${port}${path}`;
  if (!uri.startsWith('http://') && !uri.startsWith('https://')) {
    uri = `http://${uri}`;
  }

  /**
   *  NOTE: The below section should be removed and replaced with an async implementation.
   *        This is blocking the main thread while it waits for the result of the API check, meaning nothing else
   *        can run.
   */

  let apiVersion = null;
  try {
    const results      = sr('GET', uri, {
      maxRetries: 5,
      retry:      true,
      timeout:    100
    });
    const version      = JSON.parse(results.getBody('utf8')).version.number;
    const majorVersion = semver.major(version);
    let minorVersion   = semver.minor(version);
    while (true) { // eslint-disable-line no-constant-condition
      apiVersion = `${majorVersion}.${minorVersion}`;
      if (SUPPORTED_API_VERSION.includes(apiVersion)) {
        config.log.info(`${apiVersion} supported`);
        break;
      } else {
        config.log.info(`${apiVersion} is not supported version for this ES client, incrementing minor version`);
        minorVersion++;
      }
    }
  } catch (e) {
    config.log.debug(e);
  }

  if (!apiVersion) {
    throw new Error(`unable to connect to '${uri}' to get es version`);
  }

  return new elasticsearch.Client({
    host:               {host, port},
    apiVersion:         apiVersion,
    suggestCompression: true,
    log:                LogToBunyan,
    defer:              function () {
      let resolve = null;
      let reject  = null;

      const promise = new Promise((res, rej) => {
        resolve = res;
        reject = rej;
      });
      return {
        resolve: resolve,
        reject:  reject,
        promise: promise
      };
    },
    maxRetries:     3,
    requestTimeout: 60000,
    deadTimeout:    120000,
    pingTimeout:    60000
  });
};

module.exports = createEsClient;<commit_msg>better protocol handling for es client<commit_after>const _             = require('lodash');
const Promise       = require('bluebird');
const elasticsearch = require('elasticsearch');
const sr            = require('sync-request');
const bunyan        = require('bunyan');
const PrettyStream  = require('bunyan-prettystream');
const semver        = require('semver');
const config        = require('../config');

const prettyStdOut = new PrettyStream({mode: 'dev'});
prettyStdOut.pipe(process.stdout);

const LogToBunyan = function () {
  const self = this;
  const bun  = bunyan.createLogger({
    name:   `${config.FRAMEWORK_NAME}-es`,
    type:   'raw',
    level:  config.elasticsearch.logLevel,
    stream: prettyStdOut
  });

  self.error = bun.error.bind(bun);
  self.warning = bun.warn.bind(bun);
  self.info = bun.info.bind(bun);
  self.debug = bun.debug.bind(bun);
  self.trace = (method, requestUrl, body, responseBody, responseStatus) => {
    bun.trace({
      method:         method,
      requestUrl:     requestUrl,
      body:           body,
      responseBody:   responseBody,
      responseStatus: responseStatus
    });
  };
  self.close = () => {
  };
};

const DEFAULT_ELASTICSEARCH_PORT = 9200;
const SUPPORTED_API_VERSION      = _.keys(elasticsearch.Client.apis);

const createEsClient = (hostConfig) => {
  let host = hostConfig.host || 'localhost';
  const port = hostConfig.port || DEFAULT_ELASTICSEARCH_PORT;

  const protocol = (host.startsWith('https') || port === 443) ? 'https' : 'http';
  host = host.replace('https://', '').replace('http://', '');

  let path = hostConfig.path || '/';
  if (!path.startsWith('/')) {
    path = `/${path}`;
  }

  /**
   *  NOTE: The below section should be removed and replaced with an async implementation.
   *        This is blocking the main thread while it waits for the result of the API check, meaning nothing else
   *        can run.
   */
  const uri        = `${protocol}://${host}:${port}${path}`;
  let apiVersion = null;
  try {
    const results      = sr('GET', uri, {
      maxRetries: 5,
      retry:      true,
      timeout:    100
    });
    const version      = JSON.parse(results.getBody('utf8')).version.number;
    const majorVersion = semver.major(version);
    let minorVersion   = semver.minor(version);
    while (true) { // eslint-disable-line no-constant-condition
      apiVersion = `${majorVersion}.${minorVersion}`;
      if (SUPPORTED_API_VERSION.includes(apiVersion)) {
        config.log.info(`${apiVersion} supported`);
        break;
      } else {
        config.log.info(`${apiVersion} is not supported version for this ES client, incrementing minor version`);
        minorVersion++;
      }
    }
  } catch (e) {
    config.log.debug(e);
  }

  if (!apiVersion) {
    throw new Error(`unable to connect to '${uri}' to get es version`);
  }

  return new elasticsearch.Client({
    host:               {host, port, protocol, path},
    apiVersion:         apiVersion,
    suggestCompression: true,
    log:                LogToBunyan,
    defer:              function () {
      let resolve = null;
      let reject  = null;

      const promise = new Promise((res, rej) => {
        resolve = res;
        reject = rej;
      });
      return {
        resolve: resolve,
        reject:  reject,
        promise: promise
      };
    },
    maxRetries:     3,
    requestTimeout: 60000,
    deadTimeout:    120000,
    pingTimeout:    60000
  });
};

module.exports = createEsClient;<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Apigee Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var urlParse = require('url').parse;
var clone = require('lodash.clonedeep');

if (typeof window === 'undefined') {
  module.exports = convert;
} else {
  window.SwaggerConverter = window.SwaggerConverter || {
    convert: convert
  };
}

/*
 * Converts Swagger 1.2 specs file to Swagger 2.0 specs.
 * @param resourceListing {object} - root Swagger 1.2 document where it has a
 *  list of all paths
 * @param apiDeclarations {array} - a list of all resources listed in
 * resourceListing. Array of objects
 * @returns {object} - Fully converted Swagger 2.0 document
*/
function convert(resourceListing, apiDeclarations) {
  if (typeof resourceListing !== 'object') {
    throw new Error('resourceListing must be an object');
  }
  if (!Array.isArray(apiDeclarations)) {
    apiDeclarations = [];
  }

  var convertedSecurityNames = {};
  var models = {};
  var result = {
    swagger: '2.0',
    info: buildInfo(resourceListing),
    paths: {}
  };

  if (resourceListing.authorizations) {
    result.securityDefinitions = buildSecurityDefinitions(resourceListing,
      convertedSecurityNames);
  }

  if (resourceListing.basePath) {
    assignPathComponents(resourceListing.basePath, result);
  }

  extend(models, resourceListing.models);

  // Handle embedded documents
  if (Array.isArray(resourceListing.apis)) {
    result.tags = [];
    resourceListing.apis.forEach(function(api) {
      result.tags.push({
        'name': api.path.replace('.{format}', '').substring(1),
        'description': api.description });
      if (Array.isArray(api.operations)) {
        result.paths[api.path] = buildPath(api, resourceListing);
      }
    });
  }

  apiDeclarations.forEach(function(apiDeclaration) {

    // For each apiDeclaration if there is a basePath, assign path components
    // This might override previous assignments
    if (apiDeclaration.basePath) {
      assignPathComponents(apiDeclaration.basePath, result);
    }

    if (!Array.isArray(apiDeclaration.apis)) { return; }
    apiDeclaration.apis.forEach(function(api) {
      result.paths[api.path] = buildPath(api, apiDeclaration);

    });
    if (Object.keys(apiDeclaration.models).length) {
      extend(models, transformAllModels(apiDeclaration.models));
    }
  });

  if (Object.keys(models).length) {
    result.definitions = transformAllModels(models);
  }

  return result;
}

/*
 * Builds "info" section of Swagger 2.0 document
 * @param source {object} - Swagger 1.2 document object
 * @returns {object} - "info" section of Swagger 2.0 document
*/
function buildInfo(source) {
  var info = {
    version: source.apiVersion,
    title: 'Title was not specified'
  };

  if (typeof source.info === 'object') {

    if (source.info.title) {
      info.title = source.info.title;
    }

    if (source.info.description) {
      info.description = source.info.description;
    }

    if (source.info.contact) {
      info.contact = {
        email: source.info.contact
      };
    }

    if (source.info.license) {
      info.license = {
        name: source.info.license,
        url: source.info.licenseUrl
      };
    }

    if (source.info.termsOfServiceUrl) {
      info.termsOfService = source.info.termsOfServiceUrl;
    }
  }

  return info;
}

/*
 * Assigns host, basePath and schemes for Swagger 2.0 result document from
 * Swagger 1.2 basePath.
 * @param basePath {string} - the base path from Swagger 1.2
 * @param result {object} - Swagger 2.0 document
*/
function assignPathComponents(basePath, result) {
  var url = urlParse(basePath);
  result.host = url.host;
  result.basePath = url.path;
  if (url.protocol) {
    result.schemes = [url.protocol.substr(0, url.protocol.length - 1)];
  }
}

/*
 * Process a data type object.
 *
 * @see {@link https://github.com/swagger-api/swagger-spec/blob/master/versions/
 *  1.2.md#433-data-type-fields}
 *
 * @param field {object} - A data type field
 *
 * @returns {object} - Swagger 2.0 equivalent
 */
function processDataType(field) {
  field = clone(field);

  // Checking for the existence of '#/definitions/' is related to this bug:
  //   https://github.com/apigee-127/swagger-converter/issues/6
  if (field.$ref && field.$ref.indexOf('#/definitions/') === -1) {
    field.$ref = '#/definitions/' + field.$ref;
  } else if (field.items && field.items.$ref &&
             field.items.$ref.indexOf('#/definitions/') === -1) {
    field.items.$ref = '#/definitions/' + field.items.$ref;
  }

  if (field.type === 'integer') {
    if (field.minimum) {
      field.minimum = parseInt(field.minimum, 10);
    }

    if (field.maximum) {
      field.maximum = parseInt(field.maximum, 10);
    }
  } else {
    if (field.minimum) {
      field.minimum = parseFloat(field.minimum);
    }

    if (field.maximum) {
      field.maximum = parseFloat(field.maximum);
    }
  }

  if (field.defaultValue) {
    if (field.type === 'integer') {
      field.default = parseInt(field.defaultValue, 10);
    } else if (field.type === 'number') {
      field.default = parseFloat(field.defaultValue);
    } else {
      field.default = field.defaultValue;
    }

    delete field.defaultValue;
  }

  return field;
}

/*
 * Builds a Swagger 2.0 path object form a Swagger 1.2 path object
 * @param api {object} - Swagger 1.2 path object
 * @param apiDeclaration {object} - parent apiDeclaration
 * @returns {object} - Swagger 2.0 path object
*/
function buildPath(api, apiDeclaration) {
  var path = {};

  api.operations.forEach(function(oldOperation) {
    var method = oldOperation.method.toLowerCase();
    path[method] = buildOperation(oldOperation, apiDeclaration.produces,
      apiDeclaration.consumes, apiDeclaration.resourcePath);
  });

  return path;
}

/*
 * Builds a Swagger 2.0 operation object form a Swagger 1.2 operation object
 * @param oldOperation {object} - Swagger 1.2 operation object
 * @param produces {array} - from containing apiDeclaration
 * @param consumes {array} - from containing apiDeclaration
 * @returns {object} - Swagger 2.0 operation object
*/
function buildOperation(oldOperation, produces, consumes, resourcePath) {
  var operation = {
    responses: {},
    description: oldOperation.description || ''
  };
  operation.tags = [];
  operation.tags.push(resourcePath.substr(1));

  if (oldOperation.summary) {
    operation.summary = oldOperation.summary;
  }

  if (oldOperation.nickname) {
    operation.operationId = oldOperation.nickname;
  }

  if (produces) { operation.produces = produces; }
  if (consumes) { operation.consumes = consumes; }

  if (Array.isArray(oldOperation.parameters) &&
      oldOperation.parameters.length) {
    operation.parameters = oldOperation.parameters.map(function(parameter) {
      return buildParameter(processDataType(parameter));
    });
  }

  if (Array.isArray(oldOperation.responseMessages)) {
    oldOperation.responseMessages.forEach(function(oldResponse) {
      operation.responses[oldResponse.code] = buildResponse(oldResponse);
    });
  }

  if (!Object.keys(operation.responses).length) {
    operation.responses = {
      '200': {
        description: 'No response was specified'
      }
    };
  }

  return operation;
}

/*
 * Builds a Swagger 2.0 response object form a Swagger 1.2 response object
 * @param oldResponse {object} - Swagger 1.2 response object
 * @returns {object} - Swagger 2.0 response object
*/
function buildResponse(oldResponse) {
  var response = {};

  // TODO: Confirm this is correct
  response.description = oldResponse.message;

  return response;
}

/*
 * Converts Swagger 1.2 parameter object to Swagger 2.0 parameter object
 * @param oldParameter {object} - Swagger 1.2 parameter object
 * @returns {object} - Swagger 2.0 parameter object
*/
function buildParameter(oldParameter) {
  var parameter = {
    in: oldParameter.paramType,
    description: oldParameter.description,
    name: oldParameter.name,
    required: !!oldParameter.required
  };
  var primitiveTypes = [
    'string',
    'number',
    'boolean',
    'integer',
    'array',
    'void',
    'File'
  ];
  var copyProperties = [
    'default',
    'maximum',
    'minimum',
    'items'
  ];

  if (primitiveTypes.indexOf(oldParameter.type) === -1) {
    parameter.schema = {$ref: '#/definitions/' + oldParameter.type};
  } else {
    parameter.type = oldParameter.type.toLowerCase();

    copyProperties.forEach(function(name) {
      if (typeof oldParameter[name] !== 'undefined') {
        parameter[name] = oldParameter[name];
      }
    });

    if (typeof oldParameter.defaultValue !== 'undefined') {
      parameter.default = oldParameter.defaultValue;
    }
  }

  // form was changed to formData in Swagger 2.0
  if (parameter.in === 'form') {
    parameter.in = 'formData';
  }

  return parameter;
}

/*
 * Convertes Swagger 1.2 authorization definitions to Swagger 2.0 security
 *   definitions
 *
 * @param resourceListing {object} - The Swagger 1.2 Resource Listing document
 * @param convertedSecurityNames {object} - A list of original Swagger 1.2
 * authorization names and the new Swagger 2.0
 *  security names associated with it (This is required because Swagger 2.0 only
 *  supports one oauth2 flow per security definition but in Swagger 1.2 you
 *  could describe two (implicit and authorization_code).  To support this, we
 *  will create a per-flow version of each oauth2 definition, where necessary,
 *  and keep track of the new names so that when we handle security references
 *  we reference things properly.)
 *
 * @returns {object} - Swagger 2.0 security definitions
 */
function buildSecurityDefinitions(resourceListing, convertedSecurityNames) {
  var securityDefinitions = {};

  Object.keys(resourceListing.authorizations).forEach(function(name) {
    var authorization = resourceListing.authorizations[name];
    var createDefinition = function createDefinition(oName) {
      var securityDefinition = securityDefinitions[oName || name] = {
        type: authorization.type
      };

      if (authorization.passAs) {
        securityDefinition.in = authorization.passAs;
      }

      if (authorization.keyname) {
        securityDefinition.name = authorization.keyname;
      }

      return securityDefinition;
    };

    // For oauth2 types, 1.2 describes multiple "flows" in one auth and for 2.0,
    // that is not an option so we need to
    // create one security definition per flow and keep track of this mapping.
    if (authorization.grantTypes) {
      convertedSecurityNames[name] = [];

      Object.keys(authorization.grantTypes).forEach(function(gtName) {
        var grantType = authorization.grantTypes[gtName];
        var oName = name + '_' + gtName;
        var securityDefinition = createDefinition(oName);

        convertedSecurityNames[name].push(oName);

        if (gtName === 'implicit') {
          securityDefinition.flow = 'implicit';
        } else {
          securityDefinition.flow = 'accessCode';
        }

        switch (gtName) {
        case 'implicit':
          securityDefinition.authorizationUrl = grantType.loginEndpoint.url;
          break;

        case 'authorization_code':
          securityDefinition.authorizationUrl =
            grantType.tokenRequestEndpoint.url;
          securityDefinition.tokenUrl = grantType.tokenEndpoint.url;
          break;
        }

        if (authorization.scopes) {
          securityDefinition.scopes = {};

          authorization.scopes.forEach(function(scope) {
            securityDefinition.scopes[scope.scope] = scope.description ||
              ('Undescribed ' + scope.scope);
          });
        }
      });
    } else {
      createDefinition();
    }
  });

  return securityDefinitions;
}

/*
 * Transforms a Swagger 1.2 model object to a Swagger 2.0 model object
 * @param model {object} - (mutable) Swagger 1.2 model object
*/
function transformModel(model) {
  if (typeof model.properties === 'object') {
    Object.keys(model.properties).forEach(function(propertieName) {
      model.properties[propertieName] =
        processDataType(model.properties[propertieName]);
    });
  }
}

/*
 * Transfers the "models" object of Swagger 1.2 specs to Swagger 2.0 definitions
 * object
 * @param models {object} - (mutable) an object containing Swagger 1.2 objects
 * @returns {object} - transformed modles object
*/
function transformAllModels(models) {
  var modelsClone = clone(models);

  if (typeof models !== 'object') {
    throw new Error('models must be object');
  }

  var hierarchy = {};

  Object.keys(modelsClone).forEach(function(modelId) {
    var model = modelsClone[modelId];
    delete model['id'];

    transformModel(model);

    if (model.subTypes) {
      hierarchy[modelId] = model.subTypes;

      delete model.subTypes;
    }
  });

  Object.keys(hierarchy).forEach(function(parent) {
    hierarchy[parent].forEach(function(childId) {
      var childModel = modelsClone[childId];

      if (childModel) {
        var allOf = (childModel.allOf || []).concat({
          $ref: '#/definitions/' + parent
        }).concat(clone(childModel));
        for (var member in childModel) {
          delete childModel[member];
        }
        childModel.allOf = allOf;
      }
    });
  });

  return modelsClone;
}

/*
 * Extends an object with another
 * @param source {object} - object that will get extended
 * @parma distention {object} - object the will used to extend source
*/
function extend(source, distention) {
  if (typeof source !== 'object') {
    throw new Error('source must be objects');
  }

  if (typeof distention === 'object') {
    Object.keys(distention).forEach(function(key) {
      source[key] = distention[key];
    });
  }
}
<commit_msg>Fixed non-primitive model properties, so they are now referenced correctly<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2014 Apigee Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

var urlParse = require('url').parse;
var clone = require('lodash.clonedeep');

if (typeof window === 'undefined') {
  module.exports = convert;
} else {
  window.SwaggerConverter = window.SwaggerConverter || {
    convert: convert
  };
}

/*
 * Converts Swagger 1.2 specs file to Swagger 2.0 specs.
 * @param resourceListing {object} - root Swagger 1.2 document where it has a
 *  list of all paths
 * @param apiDeclarations {array} - a list of all resources listed in
 * resourceListing. Array of objects
 * @returns {object} - Fully converted Swagger 2.0 document
*/
function convert(resourceListing, apiDeclarations) {
  if (typeof resourceListing !== 'object') {
    throw new Error('resourceListing must be an object');
  }
  if (!Array.isArray(apiDeclarations)) {
    apiDeclarations = [];
  }

  var convertedSecurityNames = {};
  var models = {};
  var result = {
    swagger: '2.0',
    info: buildInfo(resourceListing),
    paths: {}
  };

  if (resourceListing.authorizations) {
    result.securityDefinitions = buildSecurityDefinitions(resourceListing,
      convertedSecurityNames);
  }

  if (resourceListing.basePath) {
    assignPathComponents(resourceListing.basePath, result);
  }

  extend(models, resourceListing.models);

  // Handle embedded documents
  if (Array.isArray(resourceListing.apis)) {
    result.tags = [];
    resourceListing.apis.forEach(function(api) {
      result.tags.push({
        'name': api.path.replace('.{format}', '').substring(1),
        'description': api.description });
      if (Array.isArray(api.operations)) {
        result.paths[api.path] = buildPath(api, resourceListing);
      }
    });
  }

  apiDeclarations.forEach(function(apiDeclaration) {

    // For each apiDeclaration if there is a basePath, assign path components
    // This might override previous assignments
    if (apiDeclaration.basePath) {
      assignPathComponents(apiDeclaration.basePath, result);
    }

    if (!Array.isArray(apiDeclaration.apis)) { return; }
    apiDeclaration.apis.forEach(function(api) {
      result.paths[api.path] = buildPath(api, apiDeclaration);

    });
    if (Object.keys(apiDeclaration.models).length) {
      extend(models, transformAllModels(apiDeclaration.models));
    }
  });

  if (Object.keys(models).length) {
    result.definitions = transformAllModels(models);
  }

  return result;
}

/*
 * Builds "info" section of Swagger 2.0 document
 * @param source {object} - Swagger 1.2 document object
 * @returns {object} - "info" section of Swagger 2.0 document
*/
function buildInfo(source) {
  var info = {
    version: source.apiVersion,
    title: 'Title was not specified'
  };

  if (typeof source.info === 'object') {

    if (source.info.title) {
      info.title = source.info.title;
    }

    if (source.info.description) {
      info.description = source.info.description;
    }

    if (source.info.contact) {
      info.contact = {
        email: source.info.contact
      };
    }

    if (source.info.license) {
      info.license = {
        name: source.info.license,
        url: source.info.licenseUrl
      };
    }

    if (source.info.termsOfServiceUrl) {
      info.termsOfService = source.info.termsOfServiceUrl;
    }
  }

  return info;
}

/*
 * Assigns host, basePath and schemes for Swagger 2.0 result document from
 * Swagger 1.2 basePath.
 * @param basePath {string} - the base path from Swagger 1.2
 * @param result {object} - Swagger 2.0 document
*/
function assignPathComponents(basePath, result) {
  var url = urlParse(basePath);
  result.host = url.host;
  result.basePath = url.path;
  if (url.protocol) {
    result.schemes = [url.protocol.substr(0, url.protocol.length - 1)];
  }
}

/*
 * Process a data type object.
 *
 * @see {@link https://github.com/swagger-api/swagger-spec/blob/master/versions/
 *  1.2.md#433-data-type-fields}
 *
 * @param field {object} - A data type field
 *
 * @returns {object} - Swagger 2.0 equivalent
 */
function processDataType(field, fixRef) {
  field = clone(field);

  // Checking for the existence of '#/definitions/' is related to this bug:
  //   https://github.com/apigee-127/swagger-converter/issues/6
  if (field.$ref && field.$ref.indexOf('#/definitions/') === -1) {
    field.$ref = '#/definitions/' + field.$ref;
  } else if (field.items && field.items.$ref &&
             field.items.$ref.indexOf('#/definitions/') === -1) {
    field.items.$ref = '#/definitions/' + field.items.$ref;
  }

  if (fixRef) {
    var primitiveTypes = [
      'string',
      'number',
      'boolean',
      'integer',
      'array',
      'void',
      'File'
    ];

    if (primitiveTypes.indexOf(field.type) === -1) {
      field = {$ref: '#/definitions/' + field.type};
    }
  }

  if (field.type === 'integer') {
    if (field.minimum) {
      field.minimum = parseInt(field.minimum, 10);
    }

    if (field.maximum) {
      field.maximum = parseInt(field.maximum, 10);
    }
  } else {
    if (field.minimum) {
      field.minimum = parseFloat(field.minimum);
    }

    if (field.maximum) {
      field.maximum = parseFloat(field.maximum);
    }
  }

  if (field.defaultValue) {
    if (field.type === 'integer') {
      field.default = parseInt(field.defaultValue, 10);
    } else if (field.type === 'number') {
      field.default = parseFloat(field.defaultValue);
    } else {
      field.default = field.defaultValue;
    }

    delete field.defaultValue;
  }

  return field;
}

/*
 * Builds a Swagger 2.0 path object form a Swagger 1.2 path object
 * @param api {object} - Swagger 1.2 path object
 * @param apiDeclaration {object} - parent apiDeclaration
 * @returns {object} - Swagger 2.0 path object
*/
function buildPath(api, apiDeclaration) {
  var path = {};

  api.operations.forEach(function(oldOperation) {
    var method = oldOperation.method.toLowerCase();
    path[method] = buildOperation(oldOperation, apiDeclaration.produces,
      apiDeclaration.consumes, apiDeclaration.resourcePath);
  });

  return path;
}

/*
 * Builds a Swagger 2.0 operation object form a Swagger 1.2 operation object
 * @param oldOperation {object} - Swagger 1.2 operation object
 * @param produces {array} - from containing apiDeclaration
 * @param consumes {array} - from containing apiDeclaration
 * @returns {object} - Swagger 2.0 operation object
*/
function buildOperation(oldOperation, produces, consumes, resourcePath) {
  var operation = {
    responses: {},
    description: oldOperation.description || ''
  };
  operation.tags = [];
  operation.tags.push(resourcePath.substr(1));

  if (oldOperation.summary) {
    operation.summary = oldOperation.summary;
  }

  if (oldOperation.nickname) {
    operation.operationId = oldOperation.nickname;
  }

  if (produces) { operation.produces = produces; }
  if (consumes) { operation.consumes = consumes; }

  if (Array.isArray(oldOperation.parameters) &&
      oldOperation.parameters.length) {
    operation.parameters = oldOperation.parameters.map(function(parameter) {
      return buildParameter(processDataType(parameter, false));
    });
  }

  if (Array.isArray(oldOperation.responseMessages)) {
    oldOperation.responseMessages.forEach(function(oldResponse) {
      operation.responses[oldResponse.code] = buildResponse(oldResponse);
    });
  }

  if (oldOperation.type && oldOperation.type !== 'void') {
    operation.responses['default'] = {
      'schema': {
        '$ref': '#/definitions/' + oldOperation.type,
      }
    };
  }

  if (!Object.keys(operation.responses).length) {
    operation.responses = {
      '200': {
        description: 'No response was specified'
      }
    };
  }

  return operation;
}

/*
 * Builds a Swagger 2.0 response object form a Swagger 1.2 response object
 * @param oldResponse {object} - Swagger 1.2 response object
 * @returns {object} - Swagger 2.0 response object
*/
function buildResponse(oldResponse) {
  var response = {};

  // TODO: Confirm this is correct
  response.description = oldResponse.message;

  return response;
}

/*
 * Converts Swagger 1.2 parameter object to Swagger 2.0 parameter object
 * @param oldParameter {object} - Swagger 1.2 parameter object
 * @returns {object} - Swagger 2.0 parameter object
*/
function buildParameter(oldParameter) {
  var parameter = {
    in: oldParameter.paramType,
    description: oldParameter.description,
    name: oldParameter.name,
    required: !!oldParameter.required
  };
  var primitiveTypes = [
    'string',
    'number',
    'boolean',
    'integer',
    'array',
    'void',
    'File'
  ];
  var copyProperties = [
    'default',
    'maximum',
    'minimum',
    'items'
  ];

  if (primitiveTypes.indexOf(oldParameter.type) === -1) {
    parameter.schema = {$ref: '#/definitions/' + oldParameter.type};
  } else {
    parameter.type = oldParameter.type.toLowerCase();

    copyProperties.forEach(function(name) {
      if (typeof oldParameter[name] !== 'undefined') {
        parameter[name] = oldParameter[name];
      }
    });

    if (typeof oldParameter.defaultValue !== 'undefined') {
      parameter.default = oldParameter.defaultValue;
    }
  }

  // form was changed to formData in Swagger 2.0
  if (parameter.in === 'form') {
    parameter.in = 'formData';
  }

  return parameter;
}

/*
 * Convertes Swagger 1.2 authorization definitions to Swagger 2.0 security
 *   definitions
 *
 * @param resourceListing {object} - The Swagger 1.2 Resource Listing document
 * @param convertedSecurityNames {object} - A list of original Swagger 1.2
 * authorization names and the new Swagger 2.0
 *  security names associated with it (This is required because Swagger 2.0 only
 *  supports one oauth2 flow per security definition but in Swagger 1.2 you
 *  could describe two (implicit and authorization_code).  To support this, we
 *  will create a per-flow version of each oauth2 definition, where necessary,
 *  and keep track of the new names so that when we handle security references
 *  we reference things properly.)
 *
 * @returns {object} - Swagger 2.0 security definitions
 */
function buildSecurityDefinitions(resourceListing, convertedSecurityNames) {
  var securityDefinitions = {};

  Object.keys(resourceListing.authorizations).forEach(function(name) {
    var authorization = resourceListing.authorizations[name];
    var createDefinition = function createDefinition(oName) {
      var securityDefinition = securityDefinitions[oName || name] = {
        type: authorization.type
      };

      if (authorization.passAs) {
        securityDefinition.in = authorization.passAs;
      }

      if (authorization.keyname) {
        securityDefinition.name = authorization.keyname;
      }

      return securityDefinition;
    };

    // For oauth2 types, 1.2 describes multiple "flows" in one auth and for 2.0,
    // that is not an option so we need to
    // create one security definition per flow and keep track of this mapping.
    if (authorization.grantTypes) {
      convertedSecurityNames[name] = [];

      Object.keys(authorization.grantTypes).forEach(function(gtName) {
        var grantType = authorization.grantTypes[gtName];
        var oName = name + '_' + gtName;
        var securityDefinition = createDefinition(oName);

        convertedSecurityNames[name].push(oName);

        if (gtName === 'implicit') {
          securityDefinition.flow = 'implicit';
        } else {
          securityDefinition.flow = 'accessCode';
        }

        switch (gtName) {
        case 'implicit':
          securityDefinition.authorizationUrl = grantType.loginEndpoint.url;
          break;

        case 'authorization_code':
          securityDefinition.authorizationUrl =
            grantType.tokenRequestEndpoint.url;
          securityDefinition.tokenUrl = grantType.tokenEndpoint.url;
          break;
        }

        if (authorization.scopes) {
          securityDefinition.scopes = {};

          authorization.scopes.forEach(function(scope) {
            securityDefinition.scopes[scope.scope] = scope.description ||
              ('Undescribed ' + scope.scope);
          });
        }
      });
    } else {
      createDefinition();
    }
  });

  return securityDefinitions;
}

/*
 * Transforms a Swagger 1.2 model object to a Swagger 2.0 model object
 * @param model {object} - (mutable) Swagger 1.2 model object
*/
function transformModel(model) {
  if (typeof model.properties === 'object') {
    Object.keys(model.properties).forEach(function(propertieName) {
      model.properties[propertieName] =
        processDataType(model.properties[propertieName], true);
    });
  }
}

/*
 * Transfers the "models" object of Swagger 1.2 specs to Swagger 2.0 definitions
 * object
 * @param models {object} - (mutable) an object containing Swagger 1.2 objects
 * @returns {object} - transformed modles object
*/
function transformAllModels(models) {
  var modelsClone = clone(models);

  if (typeof models !== 'object') {
    throw new Error('models must be object');
  }

  var hierarchy = {};

  Object.keys(modelsClone).forEach(function(modelId) {
    var model = modelsClone[modelId];
    delete model['id'];

    transformModel(model);

    if (model.subTypes) {
      hierarchy[modelId] = model.subTypes;

      delete model.subTypes;
    }
  });

  Object.keys(hierarchy).forEach(function(parent) {
    hierarchy[parent].forEach(function(childId) {
      var childModel = modelsClone[childId];

      if (childModel) {
        var allOf = (childModel.allOf || []).concat({
          $ref: '#/definitions/' + parent
        }).concat(clone(childModel));
        for (var member in childModel) {
          delete childModel[member];
        }
        childModel.allOf = allOf;
      }
    });
  });

  return modelsClone;
}

/*
 * Extends an object with another
 * @param source {object} - object that will get extended
 * @parma distention {object} - object the will used to extend source
*/
function extend(source, distention) {
  if (typeof source !== 'object') {
    throw new Error('source must be objects');
  }

  if (typeof distention === 'object') {
    Object.keys(distention).forEach(function(key) {
      source[key] = distention[key];
    });
  }
}
<|endoftext|>


<commit_before>// The M object holds utility methods for mapping and manipulating geographies
var M = {

  tileLayerUrls: {
    osm: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
    watercolor: 'http://tile.stamen.com/watercolor/{z}/{x}/{y}.jpg',
    toner: 'http://tile.stamen.com/toner/{z}/{x}/{y}.png',
    cartocdn: 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png'
  },

  // Colors for drawing map layers
  colors: [
    'cornflowerblue',
    'indianred',
    'green',
    'gold'
  ],

  recipes: {},

  // Sets up a Leaflet.js map with default settings
  setupMap: function(divId, opts={}) {
    var map = L.map(divId);
    var viewCenter = opts.viewCenter || [42.355, -71.066];
    var viewZoom = opts.viewZoom || 10;
    var tileLayer = opts.tileLayer || 'osm';

    map.setView(viewCenter, viewZoom);

    L.tileLayer(
      M.tileLayerUrls[tileLayer],
      { attribution: 'Map data © OpenStreetMap contributors', maxZoom: 18 }
    ).addTo(map);

    map.scrollWheelZoom.disable();

    return map;
  },

  // Returns a function for building properly scaled point objects
  buildPointScalingFunction: function(valMin, valMax, sizeMin, sizeMax) {
    return function(value) {
      console.log("BUILDING SCALED POINT FOR", value);
      console.log("BASED ON: ", valMin, valMax, sizeMin, sizeMax);
      var size = ( (sizeMax - sizeMin) / (valMax - valMin) ) * (value - valMin) + sizeMin;

      return new L.Point(size, size);
    }
  },

  // Draws scaled circles on the passed map, based on the dataset provided.
  // Dataset must be an array of objects with a label, value, and point key
  drawScaledCircles: function(mapObj, regions, opts={}) {

    // OPTIONS
    var showPopups = ('showPopups' in opts) ? opts.showPopups : false;
    var showLabels = ('showLabels' in opts) ? opts.showLabels : true;
    var minSize = ('scaleRange' in opts) ? opts.scaleRange[0] : 20;
    var maxSize = ('scaleRange' in opts) ? opts.scaleRange[1] : 100;

    var regionVals = regions.map(function(r) { return r.value; });
    var minVal = Math.min.apply(Math, regionVals);
    var maxVal = Math.max.apply(Math, regionVals);
    var scalePointForRange = M.buildPointScalingFunction(minVal,maxVal,minSize,maxSize);

    regions.forEach(function(region) {

      // if (region.geom) {
      //   M.drawPoly(mapObj, region.geom, {color: 'gray', weight: 1, className: 'region-poly'});
      // }

      var iconSize = scalePointForRange(region.value);

      var marker = L.marker(region.point, {
        icon: L.divIcon({
          className: 'point-icon',
          iconSize: iconSize,
          html: '

' + region.label + ':  ' + region.value + '

'
        })
      }).addTo(mapObj);

      if(showPopups) {
        marker.bindPopup(region.label, { offset: new L.Point(0,-10)})
        .on('mouseover', function(e) {
          this.openPopup();
        })
        .on('mouseout', function(e) {
          this.closePopup();
        });
      }

    });

    // if(showLabels) {
    //   $('.point-icon').mouseenter(function(e) {
    //     $(this).css({ marginTop: '-=5px'});
    //   });
    //   $('.point-icon').mouseout(function(e) {
    //     $(this).css({ marginTop: '+=5px'});
    //   });
    // }

  },

  drawPoly: function(mapObj, layer, opts={}) {
    return L.polygon(layer, opts).addTo(mapObj);
  },

  // Draw service area polygons onto the map
  drawMaps: function(mapObj, layers) {
    layers.forEach(function(layer, i) {
      if(layer != null && layer.length > 0) {
        var poly = M.drawPoly(mapObj, layer, { color: M.colors[i]});
        mapObj.fitBounds(poly.getBounds());
      }
    });
  },

  // Recipe object factory for manipulating recipe model data
  Recipe: function(params) {
    this.container = params.container;
    this._input = this.container.find('.region-input');
    this._results = this.container.find('.region-results');
    this._display = this.container.find('.region-display');
    this._recipe = params.recipeInput;
    this._searchPath = params.searchPath;
    this._ingredientLabelTag = params.ingredientLabelTag;
    this.ingredients = [];
    this._load();
    this.originalIngredients = this.ingredients.slice(); // Set original ingredients to a duplicate of ingredients, once loaded
    this._init();
    this._dump();
  }

}

// Creates a jQuery autocomplete widget for searching GeoIngredients and adding them to the GeoRecipe
M.Recipe.prototype = {
  _init: function() {
    this._display.append("");
    var that = this;
    // Set up autocomplete
    that._input
      .autocomplete({
        source: this._searchPath,
        appendTo: this._results,
        select: $.proxy(this._select, this),
        focus: function(e, ui) {
          this.value = ui.item.label;
          e.preventDefault();
        }
      })
      .autocomplete('instance')._renderItem = $.proxy(this._render, this);
  },
  _select: function(e, ui) {
    this.ingredients.push(ui.item.value);
    this._input.val(''); // Clear the input after selection
    this._dump();
    return false;
  },
  _render: function(ul, item) {
    var markup = [
      '' + item.label + ''
    ];
    ul.addClass('dropdown-menu');
    return $('
')
      .append(markup.join(''))
      .appendTo(ul);
  },

  // Loads instance variables with value of form
  _load: function() {
    this.ingredients = JSON.parse(this._recipe.val());
  },

  // Dumps instance variables to page form
  _dump: function() {
    var oldRecipe = this._recipe.val();
    var newRecipe = JSON.stringify(this.ingredients);
    this._recipe.val(newRecipe);

    // Trigger change event if recipe has changed
    if(oldRecipe !== newRecipe) {
      this._recipe.trigger('change');
    }

    // Refresh the display with new ingredient label divs
    this._display.empty();
    var that = this;
    this.ingredients.forEach(function(ingredient, i) {
      that._make_label(ingredient, i);
    });
  },

  // Creates a label and delete button for an ingredient
  _make_label: function(ingredient, i) {
    var that = this;

    // Create empty label container
    var labelTag = this._ingredientLabelTag
    this._display.append(labelTag);

    // Add a data-index value to the label container
    var container = this._display.children().last();
    container.addClass(ingredient.model);

    // Insert the ingredient description into the label
    var label = container.find('label');
    var labelText = ingredient.attributes.name;
    if(ingredient.attributes.state) { labelText += (', ' + ingredient.attributes.state) }
    label.text(labelText);

    // Set up delete button for ingredient
    var button = container.find('.btn');
    button.click(function() {
      that.ingredients.splice(i, 1);
      that._dump();
    });
  },

  // Resets recipe form to its original state
  reset: function() {
    this.ingredients = this.originalIngredients.slice();
    this._dump();
  }
};
<commit_msg>Remove opts={} from mapping.js for Uglifier<commit_after>// The M object holds utility methods for mapping and manipulating geographies
var M = {

  tileLayerUrls: {
    osm: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
    watercolor: 'http://tile.stamen.com/watercolor/{z}/{x}/{y}.jpg',
    toner: 'http://tile.stamen.com/toner/{z}/{x}/{y}.png',
    cartocdn: 'http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png'
  },

  // Colors for drawing map layers
  colors: [
    'cornflowerblue',
    'indianred',
    'green',
    'gold'
  ],

  recipes: {},

  // Sets up a Leaflet.js map with default settings
  setupMap: function(divId, opts) {
    var map = L.map(divId);
    var viewCenter = opts.viewCenter || [42.355, -71.066];
    var viewZoom = opts.viewZoom || 10;
    var tileLayer = opts.tileLayer || 'osm';

    map.setView(viewCenter, viewZoom);

    L.tileLayer(
      M.tileLayerUrls[tileLayer],
      { attribution: 'Map data © OpenStreetMap contributors', maxZoom: 18 }
    ).addTo(map);

    map.scrollWheelZoom.disable();

    return map;
  },

  // Returns a function for building properly scaled point objects
  buildPointScalingFunction: function(valMin, valMax, sizeMin, sizeMax) {
    return function(value) {
      console.log("BUILDING SCALED POINT FOR", value);
      console.log("BASED ON: ", valMin, valMax, sizeMin, sizeMax);
      var size = ( (sizeMax - sizeMin) / (valMax - valMin) ) * (value - valMin) + sizeMin;

      return new L.Point(size, size);
    }
  },

  // Draws scaled circles on the passed map, based on the dataset provided.
  // Dataset must be an array of objects with a label, value, and point key
  drawScaledCircles: function(mapObj, regions, opts) {

    // OPTIONS
    var showPopups = ('showPopups' in opts) ? opts.showPopups : false;
    var showLabels = ('showLabels' in opts) ? opts.showLabels : true;
    var minSize = ('scaleRange' in opts) ? opts.scaleRange[0] : 20;
    var maxSize = ('scaleRange' in opts) ? opts.scaleRange[1] : 100;

    var regionVals = regions.map(function(r) { return r.value; });
    var minVal = Math.min.apply(Math, regionVals);
    var maxVal = Math.max.apply(Math, regionVals);
    var scalePointForRange = M.buildPointScalingFunction(minVal,maxVal,minSize,maxSize);

    regions.forEach(function(region) {

      // if (region.geom) {
      //   M.drawPoly(mapObj, region.geom, {color: 'gray', weight: 1, className: 'region-poly'});
      // }

      var iconSize = scalePointForRange(region.value);

      var marker = L.marker(region.point, {
        icon: L.divIcon({
          className: 'point-icon',
          iconSize: iconSize,
          html: '

' + region.label + ':  ' + region.value + '

'
        })
      }).addTo(mapObj);

      if(showPopups) {
        marker.bindPopup(region.label, { offset: new L.Point(0,-10)})
        .on('mouseover', function(e) {
          this.openPopup();
        })
        .on('mouseout', function(e) {
          this.closePopup();
        });
      }

    });

    // if(showLabels) {
    //   $('.point-icon').mouseenter(function(e) {
    //     $(this).css({ marginTop: '-=5px'});
    //   });
    //   $('.point-icon').mouseout(function(e) {
    //     $(this).css({ marginTop: '+=5px'});
    //   });
    // }

  },

  drawPoly: function(mapObj, layer, opts) {
    return L.polygon(layer, opts).addTo(mapObj);
  },

  // Draw service area polygons onto the map
  drawMaps: function(mapObj, layers) {
    layers.forEach(function(layer, i) {
      if(layer != null && layer.length > 0) {
        var poly = M.drawPoly(mapObj, layer, { color: M.colors[i]});
        mapObj.fitBounds(poly.getBounds());
      }
    });
  },

  // Recipe object factory for manipulating recipe model data
  Recipe: function(params) {
    this.container = params.container;
    this._input = this.container.find('.region-input');
    this._results = this.container.find('.region-results');
    this._display = this.container.find('.region-display');
    this._recipe = params.recipeInput;
    this._searchPath = params.searchPath;
    this._ingredientLabelTag = params.ingredientLabelTag;
    this.ingredients = [];
    this._load();
    this.originalIngredients = this.ingredients.slice(); // Set original ingredients to a duplicate of ingredients, once loaded
    this._init();
    this._dump();
  }

}

// Creates a jQuery autocomplete widget for searching GeoIngredients and adding them to the GeoRecipe
M.Recipe.prototype = {
  _init: function() {
    this._display.append("");
    var that = this;
    // Set up autocomplete
    that._input
      .autocomplete({
        source: this._searchPath,
        appendTo: this._results,
        select: $.proxy(this._select, this),
        focus: function(e, ui) {
          this.value = ui.item.label;
          e.preventDefault();
        }
      })
      .autocomplete('instance')._renderItem = $.proxy(this._render, this);
  },
  _select: function(e, ui) {
    this.ingredients.push(ui.item.value);
    this._input.val(''); // Clear the input after selection
    this._dump();
    return false;
  },
  _render: function(ul, item) {
    var markup = [
      '' + item.label + ''
    ];
    ul.addClass('dropdown-menu');
    return $('
')
      .append(markup.join(''))
      .appendTo(ul);
  },

  // Loads instance variables with value of form
  _load: function() {
    this.ingredients = JSON.parse(this._recipe.val());
  },

  // Dumps instance variables to page form
  _dump: function() {
    var oldRecipe = this._recipe.val();
    var newRecipe = JSON.stringify(this.ingredients);
    this._recipe.val(newRecipe);

    // Trigger change event if recipe has changed
    if(oldRecipe !== newRecipe) {
      this._recipe.trigger('change');
    }

    // Refresh the display with new ingredient label divs
    this._display.empty();
    var that = this;
    this.ingredients.forEach(function(ingredient, i) {
      that._make_label(ingredient, i);
    });
  },

  // Creates a label and delete button for an ingredient
  _make_label: function(ingredient, i) {
    var that = this;

    // Create empty label container
    var labelTag = this._ingredientLabelTag
    this._display.append(labelTag);

    // Add a data-index value to the label container
    var container = this._display.children().last();
    container.addClass(ingredient.model);

    // Insert the ingredient description into the label
    var label = container.find('label');
    var labelText = ingredient.attributes.name;
    if(ingredient.attributes.state) { labelText += (', ' + ingredient.attributes.state) }
    label.text(labelText);

    // Set up delete button for ingredient
    var button = container.find('.btn');
    button.click(function() {
      that.ingredients.splice(i, 1);
      that._dump();
    });
  },

  // Resets recipe form to its original state
  reset: function() {
    this.ingredients = this.originalIngredients.slice();
    this._dump();
  }
};
<|endoftext|>