@@ -0,0 +1,101 @@
class @Gmaps.Google.Builders.Marker extends Gmaps.Objects.BaseBuilder

@CURRENT_INFOWINDOW: undefined
@CACHE_STORE: {}

# args:
# lat
# lng
# infowindow
# marker_title
# picture
# anchor: [x,y]
# url
# width
# height
# shadow
# anchor: [x,y]
# url
# width
# height
# provider options:
# https://developers.google.com/maps/documentation/javascript/reference?hl=fr#MarkerOptions
# internal_options
# singleInfowindow: true/false
# maxRandomDistance: null / int in meters
constructor: (@args, @provider_options = {}, @internal_options = {})->
@before_init()
@create_marker()
@create_infowindow_on_click()
@after_init()

build: ->
@marker = new(@model_class())(@serviceObject)

create_marker: ->
@serviceObject = new(@primitives().marker)(@marker_options())

create_infowindow: ->
return null unless _.isString @args.infowindow
new(@primitives().infowindow)({content: @args.infowindow })

marker_options: ->
coords = @_randomized_coordinates()
base_options =
title: @args.marker_title
position: new(@primitives().latLng)(coords[0], coords[1])
icon: @_get_picture('picture')
shadow: @_get_picture('shadow')
_.extend @provider_options, base_options

create_infowindow_on_click: ->
@addListener 'click', @infowindow_binding

infowindow_binding: =>
@constructor.CURRENT_INFOWINDOW.close() if @_should_close_infowindow()
@marker.panTo()
@infowindow ?= @create_infowindow()

return unless @infowindow?

@infowindow.open( @getServiceObject().getMap(), @getServiceObject())
@marker.infowindow ?= @infowindow
@constructor.CURRENT_INFOWINDOW = @infowindow

_get_picture: (picture_name)->
return null if !_.isObject(@args[picture_name]) || !_.isString(@args[picture_name].url)
@_create_or_retrieve_image @_picture_args(picture_name)

_create_or_retrieve_image: (picture_args) ->
if @constructor.CACHE_STORE[picture_args.url] is undefined
@constructor.CACHE_STORE[picture_args.url] = new(@primitives().markerImage)(picture_args.url, picture_args.size, picture_args.origin, picture_args.anchor , picture_args.scaledSize)

@constructor.CACHE_STORE[picture_args.url]

_picture_args: (picture_name)->
{
url: @args[picture_name].url
anchor: @_createImageAnchorPosition @args[picture_name].anchor
size: new(@primitives().size)(@args[picture_name].width, @args[picture_name].height)
scaledSize: null
origin: null
}

_createImageAnchorPosition : (anchorLocation) ->
return null unless _.isArray anchorLocation
new(@primitives().point)(anchorLocation[0], anchorLocation[1])

_should_close_infowindow: ->
@internal_options.singleInfowindow and @constructor.CURRENT_INFOWINDOW?

_randomized_coordinates: ->
return [@args.lat, @args.lng] unless _.isNumber(@internal_options.maxRandomDistance)

#gives a value between -1 and 1
random = -> (Math.random() * 2 - 1)
dx = @internal_options.maxRandomDistance * random()
dy = @internal_options.maxRandomDistance * random()
Lat = parseFloat(@args.lat) + (180/Math.PI)*(dy/6378137)
Lng = parseFloat(@args.lng) + ( 90/Math.PI)*(dx/6378137)/Math.cos(@args.lat)
return [Lat, Lng]

@@ -0,0 +1,24 @@
class @Gmaps.Google.Builders.Polygon extends Gmaps.Objects.BaseBuilder

# args:
# [
# { lat, lng}
# ]
# provider options:
# https://developers.google.com/maps/documentation/javascript/reference?hl=fr#PolygonOptions
constructor: (@args, @provider_options = {})->
@before_init()
@serviceObject = @create_polygon()
@after_init()

create_polygon: ->
new(@primitives().polygon)(@polygon_options())

polygon_options: ->
base_options =
path: @_build_path()
_.defaults base_options, @provider_options

_build_path: ->
_.map @args, (arg)=>
new(@primitives().latLng)(arg.lat, arg.lng)
@@ -0,0 +1,24 @@
class @Gmaps.Google.Builders.Polyline extends Gmaps.Objects.BaseBuilder

# args:
# [
# { lat, lng}
# ]
# provider options:
# https://developers.google.com/maps/documentation/javascript/reference?hl=fr#PolylineOptions
constructor: (@args, @provider_options = {})->
@before_init()
@serviceObject = @create_polyline()
@after_init()

create_polyline: ->
new(@primitives().polyline)(@polyline_options())

polyline_options: ->
base_options =
path: @_build_path()
_.defaults base_options, @provider_options

_build_path: ->
_.map @args, (arg)=>
new(@primitives().latLng)(arg.lat, arg.lng)
@@ -0,0 +1,17 @@
class @Gmaps.Google.Objects.Bound extends Gmaps.Base

@include Gmaps.Google.Objects.Common

constructor: (@serviceObject)->

extendWith: (array_or_object)->
collection = if _.isArray(array_or_object) then array_or_object else [ array_or_object ]
_.each collection, (object)=>
object.updateBounds(@)

# position can be:
# - [ lat, lng]
# - { lat: , lng: }
# - a google.maps.LatLng
extend: (value)->
@getServiceObject().extend @primitives().latLngFromPosition(value)
@@ -0,0 +1,9 @@
class @Gmaps.Google.Objects.Circle extends Gmaps.Base

@include Gmaps.Google.Objects.Common

constructor: (@serviceObject)->

updateBounds: (bounds)->
bounds.extend(@getServiceObject().getBounds().getNorthEast())
bounds.extend(@getServiceObject().getBounds().getSouthWest())
@@ -0,0 +1,20 @@
class @Gmaps.Google.Objects.Clusterer

constructor: (@serviceObject)->

addMarkers: (markers)->
_.each markers, (marker)=>
@addMarker(marker)

addMarker: (marker)->
@getServiceObject().addMarker(marker.getServiceObject())

clear: ->
@getServiceObject().clearMarkers()

removeMarker: (marker)->
@getServiceObject().removeMarker marker.getServiceObject()

getServiceObject: ->
@serviceObject

@@ -0,0 +1,22 @@
@Gmaps.Google.Objects.Common =

getServiceObject: ->
@serviceObject

setMap: (map)->
@getServiceObject().setMap map

clear: ->
@getServiceObject().setMap(null)

show: ->
@getServiceObject().setVisible(true)

hide: ->
@getServiceObject().setVisible(false)

isVisible: ->
@getServiceObject().getVisible()

primitives: ->
@constructor.PRIMITIVES
@@ -0,0 +1,15 @@
class @Gmaps.Google.Objects.Kml extends Gmaps.Base

constructor: (@serviceObject)->

updateBounds: (bounds)->
#even not provided by google...

setMap: (map)->
@getServiceObject().setMap map

getServiceObject: ->
@serviceObject

primitives: ->
@constructor.PRIMITIVES
@@ -0,0 +1,19 @@
class @Gmaps.Google.Objects.Map extends Gmaps.Base

constructor: (@serviceObject)->

getServiceObject: ->
@serviceObject

# position can be:
# - [ lat, lng]
# - { lat: , lng: }
# - a google.maps.LatLng
centerOn: (position)->
@getServiceObject().setCenter @primitives().latLngFromPosition(position)

fitToBounds: (boundsObject)->
@getServiceObject().fitBounds(boundsObject) unless boundsObject.isEmpty()

primitives: ->
@constructor.PRIMITIVES
@@ -0,0 +1,12 @@
class @Gmaps.Google.Objects.Marker extends Gmaps.Base

@include Gmaps.Google.Objects.Common

# @infowindow is set later, once marker is clicked
constructor: (@serviceObject)->

updateBounds: (bounds)->
bounds.extend(@getServiceObject().position)

panTo: ->
@getServiceObject().getMap().panTo @getServiceObject().getPosition()
@@ -0,0 +1,8 @@
class @Gmaps.Google.Objects.Polygon extends Gmaps.Base

@include Gmaps.Google.Objects.Common

constructor: (@serviceObject)->

updateBounds: (bounds)->
bounds.extend ll for ll in @serviceObject.getPath().getArray()
@@ -0,0 +1,8 @@
class @Gmaps.Google.Objects.Polyline extends Gmaps.Base

@include Gmaps.Google.Objects.Common

constructor: (@serviceObject)->

updateBounds: (bounds)->
bounds.extend ll for ll in @serviceObject.getPath().getArray()
@@ -0,0 +1,47 @@
@Gmaps.Google.Primitives = ->
factory = {
point: google.maps.Point
size: google.maps.Size
circle: google.maps.Circle
latLng: google.maps.LatLng
latLngBounds: google.maps.LatLngBounds
map: google.maps.Map
mapTypez: google.maps.MapTypeId
markerImage: google.maps.MarkerImage
marker: google.maps.Marker
infowindow: google.maps.InfoWindow
listener: google.maps.event.addListener
clusterer: MarkerClusterer
listenerOnce: google.maps.event.addListenerOnce
polyline: google.maps.Polyline
polygon: google.maps.Polygon
kml: google.maps.KmlLayer

addListener: (object, event_name, fn)->
factory.listener object, event_name, fn

addListenerOnce: (object, event_name, fn)->
factory.listenerOnce object, event_name, fn

mapTypes: (type)->
factory.mapTypez[type]

# position can be:
# - [ lat, lng]
# - { lat: , lng: }
# - a google.maps.LatLng
# - a gmaps4rails object
latLngFromPosition: (position)->
if _.isArray(position)
return new factory.latLng(position[0], position[1])
else
if _.isNumber(position.lat) and _.isNumber(position.lng)
return new factory.latLng(position.lat, position.lng)
else
if _.isFunction position.getServiceObject
position.getServiceObject().getPosition()
else
position
}

factory
@@ -0,0 +1,20 @@
class @Gmaps.Objects.BaseBuilder

build: ->
new(@model_class())(@serviceObject)

before_init: ->

after_init: ->

addListener: (action, fn)->
@primitives().addListener @getServiceObject(), action, fn

getServiceObject: ->
@serviceObject

primitives: ->
@constructor.PRIMITIVES

model_class: ->
@constructor.OBJECT
@@ -0,0 +1,11 @@
@Gmaps.Objects.Builders = (builderClass, objectClass, primitivesProvider)->

return {
build: (args, provider_options, internal_options)->
objectClass.PRIMITIVES = primitivesProvider
builderClass.OBJECT = objectClass
builderClass.PRIMITIVES = primitivesProvider

builder = new builderClass(args, provider_options, internal_options)
builder.build()
}
@@ -0,0 +1,148 @@
class @Gmaps.Objects.Handler

# options:
# markers:
# maxRandomDistance: null / int in meters
# singleInfowindow: true/false
# clusterer: null or object with options if you want clusters
# models: object, custom models if you have some
# builders: object, custom builders if you have some
#
constructor: (@type, options = {})->
@setPrimitives options
@setOptions options
@_cacheAllBuilders()
@resetBounds()

buildMap: (options, onMapLoad = ->)->
@map = @_builder('Map').build options, =>
@_createClusterer()
onMapLoad()

# return array of marker objects
addMarkers: (markers_data, provider_options)->
_.map markers_data, (marker_data)=>
@addMarker marker_data, provider_options

# return marker object
addMarker: (marker_data, provider_options)->
marker = @_builder('Marker').build(marker_data, provider_options, @marker_options)
marker.setMap(@getMap())
@clusterer.addMarker marker
marker

# return array of circle objects
addCircles: (circles_data, provider_options)->
_.map circles_data, (circle_data)=>
@addCircle circle_data, provider_options

# return circle object
addCircle: (circle_data, provider_options)->
@_addResource('circle', circle_data, provider_options)

# return array of polyline objects
addPolylines: (polylines_data, provider_options)->
_.map polylines_data, (polyline_data)=>
@addPolyline polyline_data, provider_options

# return polyline object
addPolyline: (polyline_data, provider_options)->
@_addResource('polyline', polyline_data, provider_options)

# return array of polygon objects
addPolygons: (polygons_data, provider_options)->
_.map polygons_data, (polygon_data)=>
@addPolygon polygon_data, provider_options

# return polygon object
addPolygon: (polygon_data, provider_options)->
@_addResource('polygon', polygon_data, provider_options)

# return array of kml objects
addKmls: (kmls_data, provider_options)->
_.map kmls_data, (kml_data)=>
@addKml kml_data, provider_options

# return kml object
addKml: (kml_data, provider_options)->
@_addResource('kml', kml_data, provider_options)

# removes markers from map
removeMarkers: (gem_markers)->
_.map gem_markers, (gem_marker)=>
@removeMarker gem_marker

# removes marker from map
removeMarker: (gem_marker)->
gem_marker.clear()
@clusterer.removeMarker(gem_marker)

fitMapToBounds: ->
@map.fitToBounds @bounds.getServiceObject()

getMap: ->
@map.getServiceObject()

setOptions: (options)->
@marker_options = _.extend @_default_marker_options(), options.markers
@builders = _.extend @_default_builders(), options.builders
@models = _.extend @_default_models(), options.models

resetBounds: ->
@bounds = @_builder('Bound').build()

setPrimitives: (options)->
@primitives = if options.primitives is undefined
@_rootModule().Primitives()
else
if _.isFunction(options.primitives) then options.primitives() else options.primitives

currentInfowindow: ->
@builders.Marker.CURRENT_INFOWINDOW

_addResource: (resource_name, resource_data, provider_options)->
resource = @_builder(resource_name).build(resource_data, provider_options)
resource.setMap(@getMap())
resource

_cacheAllBuilders: ->
that = @
_.each ['Bound', 'Circle', 'Clusterer', 'Kml', 'Map', 'Marker', 'Polygon', 'Polyline'], (kind)-> that._builder(kind)

_clusterize: ->
_.isObject @marker_options.clusterer

_createClusterer: ->
@clusterer = @_builder('Clusterer').build({ map: @getMap() }, @marker_options.clusterer )

_default_marker_options: ->
_.clone {
singleInfowindow: true
maxRandomDistance: 0
clusterer:
maxZoom: 5
gridSize: 50
}

_builder: (name)->
name = @_capitalize(name)
@["__builder#{name}"] ?= Gmaps.Objects.Builders(@builders[name], @models[name], @primitives)
@["__builder#{name}"]

_default_models: ->
models = _.clone(@_rootModule().Objects)
if @_clusterize()
models
else
models.Clusterer = Gmaps.Objects.NullClusterer
models

_capitalize: (string)->
string.charAt(0).toUpperCase() + string.slice(1)

_default_builders: ->
_.clone @_rootModule().Builders

_rootModule: ->
@__rootModule ?= Gmaps[@type]
@__rootModule
@@ -0,0 +1,5 @@
class @Gmaps.Objects.NullClusterer
addMarkers: ->
addMarker: ->
clear: ->
removeMarker: ->
@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
@@ -0,0 +1,3 @@
// Place all the styles related to the friendship controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
@@ -0,0 +1,3 @@
// Place all the styles related to the friendships controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
@@ -0,0 +1,3 @@
// Place all the styles related to the images controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
@@ -0,0 +1,84 @@
// Place all the styles related to the items controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
.friends-search{
position: relative;
width:300px;
top: -380px;
height: 200px;
left: 1260px;
border-radius: 8px ;
background-color: rgba(20, 25, 36, 0.81);
border: 4px solid white;
}
.friends-search h4{
position: relative;
font-size: 18px;
color: white;
left:70px;
top:20px;
font-family: "Interstate","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Garuda,Verdana,Tahoma,sans-serif;


}
#friendship{
width:200px;
border-color: #333;
height: 25px;
font-size: 16px;
background-color: red;
margin-top: 50px;
margin-left:40px;
resize: none;
background-color: #F5F8FA;
border: 1px solid #FCEAEC !important;
}


.find-me {
background:none!important;
border:none;
padding:0!important;
cursor: pointer;
color: white;
font-size: 20px;
font-family: "Interstate","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Garuda,Verdana,Tahoma,sans-serif;

}

.friends{
position: relative;
left:1266px;
top: -380px;
border: 1px solid black;
height: 100px;
padding-bottom: 170px;
width:200px;
border-radius: 8px;


}

.friend-name{
position: relative;
font-size: 18px;
left:110px;
top:65px;
color: black;
font-family: "Interstate","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Garuda,Verdana,Tahoma,sans-serif;

}

.add-friend{
position: relative;
font-size: 18px;
left:20px;
font-family: "Interstate","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Garuda,Verdana,Tahoma,sans-serif;
}
.added-friends{
position: relative;
font-size: 20px;
left:1300px;
top:-500px;

}
@@ -1,107 +1,283 @@
html body{

#create{
background-color: rgba(223, 224, 225, 0.3);
height: 100%;
min-width: 30%;

}

textarea:focus{
border-color: rgba(240, 240, 240, 0.9);
-webkit-box-shadow: none;
box-shadow: none;

width:500px;
height: 100px;
margin-left:20px;
margin-top: 0px;
box-shadow: 2px 2px 5px 3px #F8584E;
top:270px;
color: black;
font-family: 12px "Times New Roman", Times, serif;
background-attachment: black;
font-weight: black;
font-size: 17px;
display: none;

}

textarea#create{
display: table;
margin: auto;
min-width: 60%;
height: 30px;
border: 1px solid #FCEAEC !important;;
padding: 5px;
font-family: Tahoma, sans-serif;
font-weight: bold;
background-position: bottom right;
background-repeat: no-repeat;
margin-top:5px;
resize: none;
background-color: #F5F8FA;
margin-left:50px;
}
#create{
color:black;
}

.side-bar{
position: relative;
width: 250px;
height:400px;
background-color: #BDC7D8;
top:40px;

width: 299px;
height:120px;
top:420px;
position: fixed;
margin-left: 30px;
margin-top: 120px;
margin-left: 20px;
background-color: white;
border-radius: 8px;
z-index: 10;
background-color:rgba(20, 25, 36, 0.81);
line-height: 1.2;

}
.side-bar:hover{
background-color:#141823;

}

#due-date{
width:600px;
height: 40px;
margin-left:200px;
margin-top:50px;
display: none;

#potlock_due_date_1i{
display: none;
}
.listing-items{
width:600px;
height: 40px;
width:200px;
height: 20px;
margin-left:200px;
margin-top:50px;
display: none;


}
.post{
margin-left:300px;
margin-top:50px;
position: relative;
left:10px;
background:none!important;
border:none;
padding:0!important;
cursor: pointer;
color: black;
font-size: 20px;
font-family: "Interstate","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Garuda,Verdana,Tahoma,sans-serif;

}
select {
border: none;
color: #26f2e5;
background: transparent;
font-size: 18px;
font-weight: bold;
padding: 2px 10px;
width: 100px;
background:white;
-moz-appearance: none;
text-indent: 0.01px;
text-overflow: '';
border:1px solid rgba(245, 171, 181, 0.25);
}

#potlock_due_date_3i{
position: relative;
top: 40px;
left: 497px;
}

#potlock_due_date_2i{
position: relative;
top: 40px;
left: 497px;

}

#potlock_meal{
position: relative;
width: 150px;
-moz-border-radius: 9px 9px 9px 9px;
-webkit-border-radius: 9px 9px 9px 9px;
background: url("arrow.gif") no-repeat scroll 319px 1px white;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
top:-40px;
color: #337AB7;
font-weight: bold;
white-space: nowrap;
outline: none;
border:2px solid white;
cursor: pointer;
font-size: 16px;
left:44px;


}


.meal-label{
color:#337AB7;
margin-top: 0px;
margin-left: 44px;
font-weight: normal;
font-size: 18px;
}
.log-out{
float:right;
font-size: 12px;
.meal-label:hover{
color:#555459;
}
.meal-icon img{
position: relative;
top:10px;
right:50px;
color:#F2514E;
text-decoration: none;
font-family:"Interstate","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Garuda,Verdana,Tahoma,sans-serif;
border-left: 2px solid white;
border-right: 2px solid white;
width: 80px;
padding:2px 2px;
text-indent: 12px;
}
.NEW button{
margin-top: 30px;
font-size: 13px;
margin-left: 30px;
height: 30px;
width: 200px;
padding: 0px 30px;
padding-top: 0px;


}
.NEW h1:hover{
border-bottom: 1px solid #F2514E ;
}
.new-potluck{

border:2px solid rgba(245, 171, 181, 0.25);;
width: 550px;
height:200px;
margin-left:100px;
margin-top: 40px;
display: none
}
.new-potluck h2{
font-size: 12px;
margin-left: 240px;
}
float: left;
width:35px;
cursor: pointer;
margin-top: 10px;
left:60px;

}


.image-browser{
margin-top:80px;
margin-top:80%;
margin-left: 25px;
position: fixed;
position: relative;

}
.add-photo{

margin-left: 25px;
margin-top: 100px;
position: fixed;
}
.button {
padding:5px;
background-color:white;
color:#F2514E;
text-decoration:none;
border-left: 5px;
border-right:5px;
border-color: black;
font-family:"Interstate","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Garuda,Verdana,Tahoma,sans-serif;
font-weight: bold;
}
.button:hover{
color:#555;
}

.image_template img{
height:80px;
width:80px;
margin-left: 20px;
border-radius: 10px;
margin-top: 13px;
border: 2px solid #FFF;
position: relative;
}


.image_template3 img{
height:500px;
width:500px;
display: table;
margin: auto;
border-radius: 10px;
margin-left: 0px;
margin-top:-600px;
border:1px solid rgba(214, 245, 15, 0.96);
z-index: 99;
position: absolute;
display: none;
}
.divOverlay{
position: absolute;
top: 0px;
left: 0;
background-color: #CCC;
opacity: 0.9;
width: 100%;
height: 830px;
z-index: 98;
display: none;
}


#add-photo{
margin-left: 47px;
margin-top: 26px;
width:200px;
height:60px;
background-color:rgba(248, 140, 93, 0.39);
color:white;
font-size: 16px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
}
#add-photo2{

margin-left: 150px;
top: -120px;
line-height: 1;
color:white;
font-size: 11px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-weight: 700;
}
.camera-logo img{
width:30px;
}
.slide-icon img{
position: relative;
height: 20px;
top: -40px;
margin-left: 428px;
cursor: pointer;
display: none;
max-width:10%;

}
.form h3{
position: relative;
font-size: 18px;
top: 10px;
margin-left:80px;
color: #337AB7;
ont-family:"Interstate","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Garuda,Verdana,Tahoma,sans-serif;
max-width:35%;
}
.pen-icon img{
width:20px;
margin-top: -40px;
margin-left: 50px;
}

#side-bar2{
width:300px;
height: 700px;
margin-left: 1200px;
margin-top: -600px;
background-color:rgba(20, 25, 36, 0.51);
border-radius: 5px;
}
.form h2{
position: relative;
font-size: 20px;
left:0px;
text-transform: uppercase;
background-color: rgba(248, 140, 93, 0.39);
width: 700px;
height: 50px;
padding-top: 15px;
margin-top: 0px;
color: white;
padding-left: 80px;


}
@@ -1,4 +1,45 @@
#bar{
position: absolute;
margin-top: 0px;
width:100%;
height: 44px;
background-color:white;
position: fixed;
z-index: 10;
box-shadow: 0px 1px 0px rgba(111, 151, 182, 0.3) inset, 0px -1px 0px rgba(111, 151, 182, 0.1) inset, 0px 1px 1px rgba(75, 58, 69, 0.25);
}
.log-out{
font-size: 14px;
float:right;
margin-top: 4px;
color:#337AB7;
text-decoration: none;
font-family:"Interstate","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Garuda,Verdana,Tahoma,sans-serif;
max-width:50%;
padding:8px;
text-indent: 12px;
margin-right:4%;
}

.image_template2 img {
width:300px;
border-radius: 10px;
float:left;
margin-top: 40px;
margin-left:20px;
border: 4px solid white;
}


.logo {
float:center;
margin-top: 12px;
max-width:10%;
margin:auto;
}
.logo img {
width:80px;
}
.email{

height: 30px;
@@ -36,25 +77,8 @@
font-size: 15px;
color: white;
}
#bar{
width:100%;
height: 40px;
background-color:#1A1A1A;
top: 0px;
position: fixed;
z-index: 10;

}
.form{
position: relative;
margin-left:320px;
width:800px;
border: 1px solid #E1FFFF;
border-radius: 8px;
height: 1000px;

top:40px;
}

.btn.btn-default.forgot_password_button {
background-color: #F8584E;
@@ -101,10 +125,131 @@ top:40px;
font-size: 20px;
margin-left: 200px;
font-family: ‘Lucida Sans Unicode’, ‘Lucida Grande’, sans-serif;
}
.form{
position: relative;
display: table;
margin: auto;
top: 80px;
width: 40%;
border-radius: 5px;
right:35px;
background-color:white;
height:460px;

}


.address{

position: relative;
color: #337AB7;
width:50px;
cursor: pointer;
top: -100px;
left:280px;
font-size: 16px;
}
.address:hover{
color: #555459;
}

.map{
margin-left: 200px;

}
.profile-icon img{
width:300px;
border-radius: 10px;
float:left;
margin-top: -330px;
margin-left:2px;
}
.modal-header{
background-color: rgba(248, 140, 93, 0.39);
}
.modal-footer{
background-color: rgba(248, 140, 93, 0.39);
}
.modal-title{
color:white;
}
.name{
margin-left: 170px;
line-height: 1;
color:white;
font-size: 18px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
font-weight: 700;
margin-top: -80px;
}
.image-delete{
position: relative;
font-weight: 700;
color:#337AB7;
margin-left: 167px;
top: -20px;
font-size: 12px;

}
.map-icon img{


position: relative;
float:center;

width:38px;
cursor: pointer;
top:-132px;
left:330px;



}
textarea.address-form{
position: relative;
left: 100px;
top: -50px;
width:300px;
height: 40px;
border: 1px solid white;
padding: 5px;
font-family: Tahoma, sans-serif;
font-weight: bold;
background-position: bottom right;
background-repeat: no-repeat;
background-color: #F5F8FA;
border: 1px solid #E1E8ED;
resize:none;
font-size: 25px;

}
textarea[placeholder] {
font-family:"Interstate","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Garuda,Verdana,Tahoma,sans-serif;
font-size: 14px;
outline: none;

}
.calender-icon img{

position: relative;
width:34px;
cursor: pointer;
left:600px;
margin-top: 10px


}
.date-label{

position: relative;
width:41px;
cursor: pointer;

left:60px;
top:-20px;
color:#337AB7;
font-size: 16px;
left:635px;
}

@@ -2,5 +2,12 @@ class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :configure_permitted_parameters, if: :devise_controller?

protected

def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :first_name
end

end
@@ -0,0 +1,25 @@
class FriendshipsController < ApplicationController

def create
@friendships= Friendship.all
@friendship = current_user.friendships.build(:friend_id => params[:friend_id])
if @friendship.save
flash[:notice] = "added"
redirect_to root_path
else
render 'new'
end
end

def destroy
@friendship = current_user.friendships.find(params[:id])
@friendship.destroy
redirect_to root_path
end

def find
@friends = User.joins(:friendships).where('friends.first_name iLIKE ?', "%#{params[:friendship]}%")
# @friends = current_user.friendships.search(params[:friendship])
end
end

@@ -0,0 +1,22 @@
class ImagesController < ApplicationController
def index
@image= Image.new
@images = Image.all
end

def create
image_params= params.require(:image).permit(:image)
@image =Image.new image_params
@image.user = current_user
if @image.save
redirect_to root_path
else
render 'new'
end
end
def destroy
@image = Image.find (params[:id])
@image.destroy
redirect_to root_path
end
end
@@ -0,0 +1,37 @@
class ItemsController < ApplicationController
def new
@potlock= Potlock.find(params[:potlock_id])
@item = potlock.items.build
end

def claim
@potlock = Potlock.find(params[:potlock_id])
@item = Item.find(params[:id])
@item.user = current_user
@item.save
redirect_to new_potlock_path
end




def create
# render text: params.to_s
@potlock = Potlock.find(params[:potlock_id])
@item = @potlock.items.new(params.require(:item).permit([:name]))
if @item.save
redirect_to new_potlock_path
else
redirect_to 'new'
end
end

def destroy

@potlock = Potlock.find params[:potlock_id]
@item = Item.find params[:id]
@item.destroy
redirect_to new_potlock_path

end
end
@@ -1,15 +1,36 @@
class PotlocksController < ApplicationController
class PotlocksController < ApplicationController
before_action :authenticate_user!
def index
@potlock = Potlock.new
@potlocks = Potlock.all
@search_term = params[:friendship]
if @search_term
@users = User.where('users.first_name iLIKE ?', "%#{@search_term}%")
else
@users = User.all
end

@image= Image.new
@images= Image.all
end

def new
@item = Item.new
@potlocks =Potlock.all
@potlock= Potlock.new
@image= Image.new
@images= Image.all
@hash = Gmaps4rails.build_markers(@users) do |user, marker|
marker.lat user.latitude
marker.lng user.longitude
end
end

def create
potlock_params= params.require(:potlock).permit(:create, :due_time, :listing_items, :image)
potlock_params= params.require(:potlock).permit(:create,:due_date,:meal,:address, :longtitude, :latitude)
@potlock =Potlock.new potlock_params

if @potlock.save
redirect_to root_path
redirect_to new_potlock_path
else
render 'new'
end
@@ -18,7 +39,7 @@ def create
def destroy
@potlock = Potlock.find (params[:id])
@potlock.destroy
redirect_to root_path
redirect_to new_potlock_path
end

end
@@ -0,0 +1,23 @@
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook

omniauth_data = request.env["omniauth.auth"].to_hash
user = User.find_or_create_from_facebook(omniauth_data)
# render json: omniauth_data

if user
sign_in user
redirect_to potlocks_path, notice: "welcome"
else
redirect_to root_path, alert: "Sorry!"
end
end


def index
user = User.find_all_by_name(User.find(params[:id]).name)
@users = User.search(params[:search])
end


end
@@ -0,0 +1,2 @@
module FriendshipHelper
end
@@ -0,0 +1,2 @@
module FriendshipsHelper
end
@@ -0,0 +1,2 @@
module ImagesHelper
end
@@ -0,0 +1,2 @@
module ItemsHelper
end
@@ -0,0 +1,32 @@
class Ability
include CanCan::Ability

def initialize(user)
# Define abilities for the passed in user here. For example:
#
user ||= User.new # guest user (not logged in)
can :delete, Item, user_id: user.id
# can :manage, :all
# else
# can :read, :all
# end
#
# The first argument to `can` is the action you are giving the user
# permission to do.
# If you pass :manage it will apply to every action. Other common actions
# here are :read, :create, :update and :destroy.
#
# The second argument is the resource the user can perform the action on.
# If you pass :all it will apply to every resource. Otherwise pass a Ruby
# class of the resource.
#
# The third argument is an optional hash of conditions to further filter the
# objects.
# For example, here the user can only update published articles.
#
# can :update, Article, :published => true
#
# See the wiki for details:
# https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
end
end
@@ -0,0 +1,15 @@
class Friendship < ActiveRecord::Base
belongs_to :user, :foreign_key => :user_id
belongs_to :friend, :class_name => 'User', :foreign_key => :friend_id


def self.search(name)
if name
joins(:friends).where('friends.first_name iLIKE ?', "%#{name}%")
else
find(:all)
end
end


end
@@ -0,0 +1,6 @@
class Image < ActiveRecord::Base
validates :image, presence: true
mount_uploader :image, ImageUploader
belongs_to :user, :foreign_key => 'user_id'

end
@@ -0,0 +1,4 @@
class Item < ActiveRecord::Base
belongs_to :potlock
belongs_to :user
end
@@ -0,0 +1,3 @@
class ListingItem < ActiveRecord::Base
belongs_to :potlocks
end
@@ -1,3 +1,8 @@
class Potlock < ActiveRecord::Base
mount_uploader :image, ImageUploader
belongs_to :user
geocoded_by :address
after_validation :geocode
has_many :items, :dependent => :destroy


end
@@ -1,6 +1,66 @@
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
end
geocoded_by :address
after_validation :geocode

#validates :user_id, presence: true, :uniqueness => true
#validate :images_limit

devise :database_authenticatable, :registerable, :omniauthable,
:recoverable, :rememberable, :trackable, :validatable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable

has_many :images
has_many :potlocks
has_many :items
has_many :friendships
has_many :friends, :through => :friendships
has_many :inverse_friendships, :class_name => "Freindship", :foreign_key => "friend_id"
has_many :inverse_friendships, :through => :inverse_friendships, :source => :user






def image
images.order('created_at DESC').first
end
serialize :omniauth_data

def email_required? #bypasses devise email required validation(already with facebook)
false
end
def password_required?
provider.nil? #bypasses devise password required validation(already with facebook)
end



def self.find_or_create_from_facebook(omniauth_data)

user = User.where(provider: :facebook, uid: omniauth_data["uid"]).first
unless user
name = omniauth_data["info"]["name"].split
image = omniauth data["info"]["image"]
user = User.create(provider: :facebook,
uid: omniauth_data["uid"],
email: omniauth_data["info"]["email"],
image: image[1],
first_name: name[0],
oauth_token: omniauth_data["token"],
oauth_expires_at: Time.at(omniauth_data["credentials"]["expires_at"]),
omniauth_raw_data: omniauth_data)



end
user
end

end



@@ -4,7 +4,7 @@
class ImageUploader < CarrierWave::Uploader::Base

# Include RMagick or MiniMagick support:
#include CarrierWave::RMagick
# include CarrierWave::RMagick
include CarrierWave::MiniMagick

# Choose what kind of storage to use for this uploader:
@@ -34,8 +34,8 @@ def store_dir

# Create different versions of your uploaded files:
version :thumb do
process :resize_to_fit => [200, 200]
end
process :resize_to_fit => [300, 300]
end

# Add a white list of extensions which are allowed to be uploaded.
# For images you might use something like this:
@@ -22,6 +22,8 @@
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>



<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password, autocomplete: "off" %>
@@ -5,14 +5,20 @@
<%= link_to "Log in", new_session_path(resource_name), class: "sign-up-link-log-in-link2" %>
</div>

<!-- <h1> hey </h1> -->


<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= devise_error_messages! %>

<div class="field">
<%= f.text_field :first_name, autofocus: true, placeholder: "add your name", class: "email" %>
</div>

<div class="field">

<%= f.email_field :email, autofocus: true, placeholder: "email adress", class: "email" %>

</div>

<div class="field">
@@ -27,7 +33,6 @@

<%= f.password_field :password_confirmation, autocomplete: "off",placeholder: "Password confirmation", class: "password" %>
</div>

<div class="actions">
<%= f.submit "Sign up", class: "btn btn-default sign-up " %>
</div>
@@ -7,14 +7,16 @@

<%= link_to "Sign up", new_registration_path(resource_name), class: "sign-up-link-log-in-link" %>
<%= link_to "Log in", new_session_path(resource_name), class: "sign-up-link-log-in-link2" %>
<%= link_to "Log in with facebook ", user_omniauth_authorize_path(provider: :facebook), class: "sign-up-link-log-in-link2" %>
</div>


<div class="row">
<div class="col-xs-12">
<div id="background-image">
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="field">
<%= f.email_field :email, autofocus: true, placeholder: "email address", class: "email" %>
</div>
</div>

<div class="field">
<%= f.password_field :password, autocomplete: "off", placeholder: "password", class: "password" %>
@@ -33,6 +35,6 @@
<%= render "devise/shared/links" %>
<% end %>


</div>
</div>

</div>
Empty file.
Empty file.
@@ -0,0 +1,6 @@
<%= form_for [potlock, item], class: 'form' do |f| %>
<%= f.text_area :name %>
<%= f.submit %>
<% end %>
@@ -0,0 +1,13 @@
<%= render partial: 'items/form', locals: { item: @item } %>


<div id="side-bar2">
<% form_tag user_session_path, :method => 'get' do %>
<p>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil %>
</p>
<% end %>

</div>

@@ -1,19 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>

<title>Potluck</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
<script src="//maps.google.com/maps/api/js?v=3.13&amp;sensor=false&amp;libraries=geometry" type="text/javascript"></script>
<script src='//google-maps-utility-library-v3.googlecode.com/svn/tags/markerclustererplus/2.0.14/src/markerclusterer_packed.js' type='text/javascript'></script>
</head>
<body >
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">


</button>


<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>

<%= flash[:notice] || flash[:alert] %>
@@ -1,43 +1,219 @@
<link href='http://fonts.googleapis.com/css?family=Raleway:400,600,800' rel='stylesheet' type='text/css'>
<link href='http://fonts.googleapis.com/css?family=Indie+Flower&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
<div class="divOverlay">
</div>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>


<div id= "bar">
<%=link_to "Log out", destroy_user_session_path, :method => :delete, class: "log-out" %>
<div class="row">
<div class="col-md-12">
<%=link_to "Log out", destroy_user_session_path, :method => :delete, class: "log-out" %>
<div class="logo">
<img src="https://fbcdn-sphotos-h-a.akamaihd.net/hphotos-ak-xpf1/v/t34.0-12/10994726_10155228223160080_1910018901_n.jpg?oh=3e5c4b37406b6912d10b3dd75a5e8b8e&oe=54F8A592&__gda__=1425523203_d0f2a36cb8de9038e7f1a9a99a073652">
</div>
</div>
</div>
<%= form_for Potlock.new do |f| %>
<%= f.file_field :image, class: "image-browser"%>
<%= f.submit 'add-photo', class: "add-photo"%>
<%end%>

<div class="image_template2">

<% if current_user.image %>
<%= image_tag current_user.image.image.url(:thumb) %>
<%end%>
</div>
</div>
</div>
</div>


<%= form_for Potlock.new do |f| %>
<div class="side-bar"></div>
<div class="form">




<div class="side-bar">
<div class="profile-icon">
<img src="http://locate.mk/images/profile-icon.png">
</div>
<div class="image_template">

<% if current_user.image %>
<%= image_tag current_user.image.image.url(:thumb) %>
<%= link_to "Delete Photo",current_user.image, method: :delete, class: "image-delete" %>
<div class="name">
<%= current_user.first_name%>
</div>
<%#= current_user.email %>
</div>
<% end %>
<button type="button" class="btn btn-link " id="add-photo2" data-toggle="modal" data-target="#image-uploader">
Change your photo
</button>
</div>

<div class= "NEW">
<button > Hello </button>


<button type="button" class="btn btn-link " id="add-photo" data-toggle="modal" data-target="#image-uploader">
<div class="camera-logo">
<img src="http://www.clker.com/cliparts/O/c/P/C/o/K/white-camera-hi.png">
</div>
Add your photo
</button>

<div id="image-uploader" class="modal fade">
<%= form_for Image.new do |f| %>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"> Add your potluck photo</h4>
</div>
<div class="modal-body">

<%= f.file_field :image, class: "image-browser"%>

</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<input type="submit" class="btn btn-primary" value="Upload">
</div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
<%end%>
</div><!-- /.modal -->
</div>

<div class="new-potluck">
<h2> what is ? </h2>
<hr>
<%=f.text_area :create, id: "create", placeholder: "" %> </br>
</div>
<%=f.text_field :due_date, id: "due-date" %> </br>
<%=f.text_field :listing_items, class: "listing-items" %> </br>
<%= f.submit 'Post', class: "post"%>

<!--<div class= "NEW">
<button class="button" id="save">Make a new potluck</button>
</div> -->



<%= form_for Potlock.new do |f| %>

<div class="form">
<h2> Start a new potluck </h2>
<h3> Name your potluck!</h3>
<div class="pen-icon">
<img src="http://simpleicon.com/wp-content/uploads/pen-15.png">
</div>
<%=f.text_area :create, id: "create", placeholder: "" %><hr>
<div class="slide-icon">
<img src="https://cdn1.iconfinder.com/data/icons/mobiletouch-gestures/500/up-512.png">
</div>
<div class="meal-icon">
<img src="http://www.amidonsolutions.com/eugenia/images/icon_dining.png
">
</div>
<div class="calender-icon">
<img src ="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSPjSWjgGg6h0TsQjnsQ32DBgh_bDEyUfQclGA5KrigW7VJOGI8">
</div>
<%=f.date_select :due_date, class: "due-date" %> </br>
<%=f.label :due_date, "Time", class: "date-label"%>
<%#=f.label :meal, "Meal", class: "meal-label" %> <div id="meal"> <%=f.select :meal,options_for_select(%w[Meal Breakfast Brunch Lunch Dinner ]) %> </br>
<div class="map-icon">
<img src="https://cdn4.iconfinder.com/data/icons/pictype-free-vector-icons/16/location-alt-512.png">
<%=f.label :address, "Place", class: "address" %> <%=f.text_area :address, placeholder: "add your address", class: "address-form" %>
<div class= "bottom">
<%= f.submit 'Create', class: "post"%>
</div>
</div>
<div class="image_template3">
<% if current_user.image %>
<%= image_tag current_user.image.image.url(:thumb) %>
<%end%>
</div>
</div>
</div>
<hr size="50" >
</div>
</div>
<%end%>


<div class= "friends-search">
<h4> Find your friends </h4>
<%= form_tag potlocks_path, :method => 'get' do %>
<%= text_field_tag :friendship, @search_term %>
<%= submit_tag "find", :first_name => nil, class: "find-me"%>
<% end %>
</div>

<% for user in @users %>
<div class="friends">
<div class="friend-name">
<%= user.first_name%></br>
</div>
<div class="image_template">
<% if user.image %></br>
<%= image_tag user.image.image.url %></br>
<% end %>
</div>

<div class="add-friend">
<%= link_to "add friend", friendships_path(:friend_id => user.id), :method => :post %>
<br/>
</div>
</div>
<% end %>

</div>


<% current_user.friendships.each do |friendship| %>
<h2><%= friendship.friend && friendship.friend.first_name%> </h2>

<% if friendship.friend %>
<%= friendship.friend.first_name%>
<% if friendship.friend.image %>
<%= image_tag user.image.image.url %>
<% end%>
</div>
<%= friendship.friend.first_name if friendship.friend %></br>
<%= link_to "unfriend",friendship, :method => :delete %></br>
<%end %>
<% end %>
<%#=f.text_field :listing_items, class: "listing-items" %> </br>













<script type="text/javascript">
$(document).ready(function(){
if (<%=current_user.image.blank? %>){
$(".profile-icon").css("display", "block");
$("#add-photo2").css("display","none");

}
else {

$(".profile-icon").css("display","none");
$("#add-photo").css("display","none");


}
});
</script>







<% @potlocks.each do |potlock| %>
<div class="potlock">
<%= potlock.create %> </br>
<%= image_tag potlock.image.url(:thumb) unless potlock.image.blank? %>
</div>
<%= link_to "delete",potlock, method: :delete, class: "btn btn-default potlock-delete" %>
<% end %>
</div>
@@ -0,0 +1,57 @@
<% @potlocks.each do |potlock| %>
<%= potlock.create %> </br>
<%= potlock.meal %><br>
<%= potlock.address %>
<%= potlock.due_date.strftime("%A %b %d") %><br>
<%= render partial: 'items/form', locals: {potlock: potlock, item: Item.new} %>
<% potlock.items.each do |item| %>
<%= item.name %><br>

<%=link_to "delete item",potlock_item_path(potlock, item), method: :delete%>
<%=link_to "select",claim_potlock_item_path(potlock, item), method: :post%>
selected by: <%= item.user.try(:first_name) || '' %>
<%end %>
<%= link_to "delete",potlock, method: :delete, class: "btn btn-default potlock-delete" %>
<% end %>


<div class="map" style='width: 200px;'>
<div id="map" style='width: 200px; height: 200px;'></div>
</div>

<script>
$(document).ready(function(){

var handler = Gmaps.build('Google');
//var bounds = new google.maps.LatLngBounds();
handler.buildMap({ internal: {id: 'map'}}, function(){
var markers = handler.addMarkers([
{ "lat": <%= @potlocks.blank? ? 50 : @potlocks.first.latitude %>,
"lng": <%= @potlocks.blank? ? 50 : @potlocks.first.longitude %>,
}
]);
handler.bounds.extendWith(markers);
handler.fitMapToBounds();

handler.getMap().setZoom(12);

// gmap.setZoom( Math.max(6, gmap.getZoom()) );


});


if (<%= @potlocks.blank? %>) {
$(".map").css("display", "none");
}
else {
$(".map").css("display", "block");
}
});
</script>
@@ -0,0 +1,14 @@
<!-- <div class="added-friends">
<%# if friendship.friend %>
<%= friendship.friend.first_name%>
</div>
<div class="image_template">
<%# if friendship.friend.image %>
<%= image_tag user.image.image.url %>
<%# end%>
</div>
<%#= friendship.friend.first_name if friendship.friend %></br>
<%#= link_to "unfriend",friendship, :method => :delete %></br>
<%# end %>

</div>
@@ -233,6 +233,8 @@
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
config.omniauth :facebook, ENV["FACEBOOK_APP_KEY"], ENV["FACEBOOK_APP_SECRET"]


# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or
@@ -1,13 +1,27 @@
Rails.application.routes.draw do
devise_for :users
devise_for :users,
controllers: {omniauth_callbacks:"users/omniauth_callbacks"}
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".

# You can have the root of your site routed with "root"
# root 'welcome#index'

root 'potlocks#index'
resources :potlocks
resources :potlocks do
resources :items do
member do
post :claim
end
end
end
resources :friendships do
post :find, on: :collection
end
# resources :friendships, :collection => { :index => :get }
resources :images






This file was deleted.

@@ -0,0 +1,5 @@
class AddImageToUsers < ActiveRecord::Migration
def change
add_column :users, :image, :string
end
end
@@ -0,0 +1,8 @@
class CreateImages < ActiveRecord::Migration
def change
create_table :images do |t|

t.timestamps null: false
end
end
end
@@ -0,0 +1,5 @@
class AddImageToImages < ActiveRecord::Migration
def change
add_column :images, :image, :string
end
end
@@ -0,0 +1,5 @@
class AddPhotoUsers < ActiveRecord::Migration
def change
add_column :images, :user_id, :integer
end
end
@@ -0,0 +1,5 @@
class AddDetailsToUsers < ActiveRecord::Migration
def change
add_column :users, :first_name, :string
end
end
@@ -0,0 +1,5 @@
class AddColumnToPotlock < ActiveRecord::Migration
def change
add_column :potlocks, :meal, :string
end
end
@@ -0,0 +1,7 @@
class AddGeocodingFieldsToPotlocks < ActiveRecord::Migration
def change
add_column :potlocks, :address, :string
add_column :potlocks, :longitude, :float
add_column :potlocks, :latitude, :float
end
end
@@ -0,0 +1,7 @@
class AddGeocodingAttrsToUsers < ActiveRecord::Migration
def change
add_column :users, :address, :string
add_column :users, :longitude, :float
add_column :users, :latitude, :float
end
end
@@ -0,0 +1,6 @@
class ChangePotluckDueDateToDate < ActiveRecord::Migration
def change
remove_column :potlocks, :due_date, :string
add_column :potlocks, :due_date, :datetime
end
end
@@ -0,0 +1,11 @@
class AddOmniauthFieldsToUsers < ActiveRecord::Migration
def change
add_column :users, :provider, :string
add_column :users, :uid, :string
add_column :users, :facebook_consumer, :string
add_column :users, :facebook_consumer_secret, :string
add_column :users, :omniauth_raw_data, :text

add_index :users, [:provider, :uid]
end
end
@@ -0,0 +1,8 @@
class RemoveColumnsFromUsersTabel < ActiveRecord::Migration
def change
remove_column :users, :facebook_consumer
remove_column :users, :facebook_consumer_secret
remove_column :users, :omniauth_raw_data

end
end
@@ -0,0 +1,6 @@
class AddNewColumnsTo < ActiveRecord::Migration
def change
add_column :users, :oauth_token, :text
add_column :users, :oauth_expires_at, :datetime
end
end
@@ -0,0 +1,5 @@
class AddListingItemsToPotlock < ActiveRecord::Migration
def change
add_column :potlocks, :listing_items, :text
end
end
@@ -0,0 +1,5 @@
class AddSelectedToPotlocks < ActiveRecord::Migration
def change
add_column :potlocks, :selected, :boolean
end
end
@@ -0,0 +1,6 @@
class AddUserToPotlock < ActiveRecord::Migration
def change
add_reference :potlocks, :user, index: true
add_foreign_key :potlocks, :users
end
end
@@ -0,0 +1,13 @@
class CreateItems < ActiveRecord::Migration
def change
create_table :items do |t|
t.string :name
t.references :user, index: true
t.references :potlock, index: true

t.timestamps null: false
end
add_foreign_key :items, :potlocks
add_foreign_key :items, :users
end
end
@@ -0,0 +1,10 @@
class CreateFriendships < ActiveRecord::Migration
def change
create_table :friendships do |t|
t.integer :user_id
t.integer :friend_id

t.timestamps null: false
end
end
end
@@ -11,20 +11,57 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20150218051343) do
ActiveRecord::Schema.define(version: 20150302212247) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

create_table "friendships", force: :cascade do |t|
t.integer "user_id"
t.integer "friend_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

create_table "images", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image"
t.integer "user_id"
end

create_table "items", force: :cascade do |t|
t.string "name"
t.integer "user_id"
t.integer "potlock_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end

add_index "items", ["potlock_id"], name: "index_items_on_potlock_id", using: :btree
add_index "items", ["user_id"], name: "index_items_on_user_id", using: :btree

create_table "listing_items_tables", force: :cascade do |t|
t.string "food_choice"
end

create_table "potlocks", force: :cascade do |t|
t.string "create"
t.string "due_date"
t.string "listing_items"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image"
t.string "meal"
t.string "address"
t.float "longitude"
t.float "latitude"
t.datetime "due_date"
t.text "listing_items"
t.boolean "selected"
t.integer "user_id"
end

add_index "potlocks", ["user_id"], name: "index_potlocks_on_user_id", using: :btree

create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
@@ -38,9 +75,22 @@
t.inet "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "image"
t.string "first_name"
t.string "address"
t.float "longitude"
t.float "latitude"
t.string "provider"
t.string "uid"
t.text "oauth_token"
t.datetime "oauth_expires_at"
end

add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["provider", "uid"], name: "index_users_on_provider_and_uid", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree

add_foreign_key "items", "potlocks"
add_foreign_key "items", "users"
add_foreign_key "potlocks", "users"
end
Binary file not shown.
@@ -0,0 +1,202 @@

Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/

TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

1. Definitions.

"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.

"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.

"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.

"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.

"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.

"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.

"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).

"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.

"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."

"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.

2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.

3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.

4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:

(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and

(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and

(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and

(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.

You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.

5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.

6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.

7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.

8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.

9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

END OF TERMS AND CONDITIONS

APPENDIX: How to apply the Apache License to your work.

To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright [yyyy] [name of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
@@ -0,0 +1,5 @@
ElasticSearch
Copyright 2009-2011 ElasticSearch and Shay Banon

This product includes software developed by The Apache Software
Foundation (http://www.apache.org/).
@@ -0,0 +1,223 @@
h1. ElasticSearch

h2. A Distributed RESTful Search Engine

h3. "http://www.elasticsearch.org":http://www.elasticsearch.org

ElasticSearch is a distributed RESTful search engine built for the cloud. Features include:

* Distributed and Highly Available Search Engine.
** Each index is fully sharded with a configurable number of shards.
** Each shard can have one or more replicas.
** Read / Search operations performed on either one of the replica shard.
* Multi Tenant with Multi Types.
** Support for more than one index.
** Support for more than one type per index.
** Index level configuration (number of shards, index storage, ...).
* Various set of APIs
** HTTP RESTful API
** Native Java API.
** All APIs perform automatic node operation rerouting.
* Document oriented
** No need for upfront schema definition.
** Schema can be defined per type for customization of the indexing process.
* Reliable, Asynchronous Write Behind for long term persistency.
* (Near) Real Time Search.
* Built on top of Lucene
** Each shard is a fully functional Lucene index
** All the power of Lucene easily exposed through simple configuration / plugins.
* Per operation consistency
** Single document level operations are atomic, consistent, isolated and durable.
* Open Source under Apache 2 License.

h2. Getting Started

First of all, DON'T PANIC. It will take 5 minutes to get the gist of what ElasticSearch is all about.

h3. Installation

* "Download":http://www.elasticsearch.org/download and unzip the ElasticSearch official distribution.
* Run @bin/elasticsearch -f@ on unix, or @bin/elasticsearch.bat@ on windows.
* Run @curl -X GET http://localhost:9200/@.
* Start more servers ...

h3. Indexing

Lets try and index some twitter like information. First, lets create a twitter user, and add some tweets (the @twitter@ index will be created automatically):

<pre>
curl -XPUT 'http://localhost:9200/twitter/user/kimchy' -d '{ "name" : "Shay Banon" }'

curl -XPUT 'http://localhost:9200/twitter/tweet/1' -d '
{
"user": "kimchy",
"postDate": "2009-11-15T13:12:00",
"message": "Trying out Elastic Search, so far so good?"
}'

curl -XPUT 'http://localhost:9200/twitter/tweet/2' -d '
{
"user": "kimchy",
"postDate": "2009-11-15T14:12:12",
"message": "Another tweet, will it be indexed?"
}'
</pre>

Now, lets see if the information was added by GETting it:

<pre>
curl -XGET 'http://localhost:9200/twitter/user/kimchy?pretty=true'
curl -XGET 'http://localhost:9200/twitter/tweet/1?pretty=true'
curl -XGET 'http://localhost:9200/twitter/tweet/2?pretty=true'
</pre>

h3. Searching

Mmm search..., shouldn't it be elastic?
Lets find all the tweets that @kimchy@ posted:

<pre>
curl -XGET 'http://localhost:9200/twitter/tweet/_search?q=user:kimchy&pretty=true'
</pre>

We can also use the JSON query language ElasticSearch provides instead of a query string:

<pre>
curl -XGET 'http://localhost:9200/twitter/tweet/_search?pretty=true' -d '
{
"query" : {
"text" : { "user": "kimchy" }
}
}'
</pre>

Just for kicks, lets get all the documents stored (we should see the user as well):

<pre>
curl -XGET 'http://localhost:9200/twitter/_search?pretty=true' -d '
{
"query" : {
"matchAll" : {}
}
}'
</pre>

We can also do range search (the @postDate@ was automatically identified as date)

<pre>
curl -XGET 'http://localhost:9200/twitter/_search?pretty=true' -d '
{
"query" : {
"range" : {
"postDate" : { "from" : "2009-11-15T13:00:00", "to" : "2009-11-15T14:00:00" }
}
}
}'
</pre>

There are many more options to perform search, after all, its a search product no? All the familiar Lucene queries are available through the JSON query language, or through the query parser.

h3. Multi Tenant - Indices and Types

Maan, that twitter index might get big (in this case, index size == valuation). Lets see if we can structure our twitter system a bit differently in order to support such large amount of data.

ElasticSearch support multiple indices, as well as multiple types per index. In the previous example we used an index called @twitter@, with two types, @user@ and @tweet@.

Another way to define our simple twitter system is to have a different index per user (though note that an index has an overhead). Here is the indexing curl's in this case:

<pre>
curl -XPUT 'http://localhost:9200/kimchy/info/1' -d '{ "name" : "Shay Banon" }'

curl -XPUT 'http://localhost:9200/kimchy/tweet/1' -d '
{
"user": "kimchy",
"postDate": "2009-11-15T13:12:00",
"message": "Trying out Elastic Search, so far so good?"
}'

curl -XPUT 'http://localhost:9200/kimchy/tweet/2' -d '
{
"user": "kimchy",
"postDate": "2009-11-15T14:12:12",
"message": "Another tweet, will it be indexed?"
}'
</pre>

The above index information into the @kimchy@ index, with two types, @info@ and @tweet@. Each user will get his own special index.

Complete control on the index level is allowed. As an example, in the above case, we would want to change from the default 5 shards with 1 replica per index, to only 1 shard with 1 replica per index (== per twitter user). Here is how this can be done (the configuration can be in yaml as well):

<pre>
curl -XPUT http://localhost:9200/another_user/ -d '
{
"index" : {
"numberOfShards" : 1,
"numberOfReplicas" : 1
}
}'
</pre>

Search (and similar operations) are multi index aware. This means that we can easily search on more than one
index (twitter user), for example:

<pre>
curl -XGET 'http://localhost:9200/kimchy,another_user/_search?pretty=true' -d '
{
"query" : {
"matchAll" : {}
}
}'
</pre>

Or on all the indices:

<pre>
curl -XGET 'http://localhost:9200/_search?pretty=true' -d '
{
"query" : {
"matchAll" : {}
}
}'
</pre>

{One liner teaser}: And the cool part about that? You can easily search on multiple twitter users (indices), with different boost levels per user (index), making social search so much simpler (results from my friends rank higher than results from my friends friends).

h3. Distributed, Highly Available

Lets face it, things will fail....

ElasticSearch is a highly available and distributed search engine. Each index is broken down into shards, and each shard can have one or more replica. By default, an index is created with 5 shards and 1 replica per shard (5/1). There are many topologies that can be used, including 1/10 (improve search performance), or 20/1 (improve indexing performance, with search executed in a map reduce fashion across shards).

In order to play with Elastic Search distributed nature, simply bring more nodes up and shut down nodes. The system will continue to serve requests (make sure you use the correct http port) with the latest data indexed.

h3. Where to go from here?

We have just covered a very small portion of what ElasticSearch is all about. For more information, please refer to: .

h3. Building from Source

ElasticSearch uses "Maven":http://maven.apache.org for its build system.

In order to create a distribution, simply run the @mvn package -DskipTests@ command in the cloned directory.

The distribution will be created under @target/releases@.

h1. License

<pre>
This software is licensed under the Apache 2 license, quoted below.

Copyright 2009-2012 Shay Banon and ElasticSearch <http://www.elasticsearch.org>

Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
</pre>
@@ -0,0 +1,181 @@
#!/bin/sh

# OPTIONS:
# -f: start in the foreground
# -p <filename>: log the pid to a file (useful to kill it later)

# CONTROLLING STARTUP:
#
# This script relies on few environment variables to determine startup
# behavior, those variables are:
#
# ES_CLASSPATH -- A Java classpath containing everything necessary to run.
# JAVA_OPTS -- Additional arguments to the JVM for heap size, etc
# ES_JAVA_OPTS -- External Java Opts on top of the defaults set
#
#
# Optionally, exact memory values can be set using the following values, note,
# they can still be set using the `ES_JAVA_OPTS`. Sample format include "512m", and "10g".
#
# ES_HEAP_SIZE -- Sets both the minimum and maximum memory to allocate (recommended)
#
# As a convenience, a fragment of shell is sourced in order to set one or
# more of these variables. This so-called `include' can be placed in a
# number of locations and will be searched for in order. The lowest
# priority search path is the same directory as the startup script, and
# since this is the location of the sample in the project tree, it should
# almost work Out Of The Box.
#
# Any serious use-case though will likely require customization of the
# include. For production installations, it is recommended that you copy
# the sample to one of /usr/share/elasticsearch/elasticsearch.in.sh,
# /usr/local/share/elasticsearch/elasticsearch.in.sh, or
# /opt/elasticsearch/elasticsearch.in.sh and make your modifications there.
#
# Another option is to specify the full path to the include file in the
# environment. For example:
#
# $ ES_INCLUDE=/path/to/in.sh elasticsearch -p /var/run/es.pid
#
# Note: This is particularly handy for running multiple instances on a
# single installation, or for quick tests.
#
# If you would rather configure startup entirely from the environment, you
# can disable the include by exporting an empty ES_INCLUDE, or by
# ensuring that no include files exist in the aforementioned search list.
# Be aware that you will be entirely responsible for populating the needed
# environment variables.

CDPATH=""
SCRIPT="$0"

# SCRIPT may be an arbitrarily deep series of symlinks. Loop until we have the concrete path.
while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
# Drop everything prior to ->
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done

# determine elasticsearch home
ES_HOME=`dirname "$SCRIPT"`/..

# make ELASTICSEARCH_HOME absolute
ES_HOME=`cd "$ES_HOME"; pwd`


# If an include wasn't specified in the environment, then search for one...
if [ "x$ES_INCLUDE" = "x" ]; then
# Locations (in order) to use when searching for an include file.
for include in /usr/share/elasticsearch/elasticsearch.in.sh \
/usr/local/share/elasticsearch/elasticsearch.in.sh \
/opt/elasticsearch/elasticsearch.in.sh \
~/.elasticsearch.in.sh \
`dirname "$0"`/elasticsearch.in.sh; do
if [ -r "$include" ]; then
. "$include"
break
fi
done
# ...otherwise, source the specified include.
elif [ -r "$ES_INCLUDE" ]; then
. "$ES_INCLUDE"
fi

if [ -x "$JAVA_HOME/bin/java" ]; then
JAVA="$JAVA_HOME/bin/java"
else
JAVA=java
fi

if [ -z "$ES_CLASSPATH" ]; then
echo "You must set the ES_CLASSPATH var" >&2
exit 1
fi

# Special-case path variables.
case `uname` in
CYGWIN*)
ES_CLASSPATH=`cygpath -p -w "$ES_CLASSPATH"`
ES_HOME=`cygpath -p -w "$ES_HOME"`
;;
esac

launch_service()
{
pidpath=$1
foreground=$2
props=$3
es_parms="-Delasticsearch"

if [ "x$pidpath" != "x" ]; then
es_parms="$es_parms -Des.pidfile=$pidpath"
fi

# The es-foreground option will tell ElasticSearch not to close stdout/stderr, but it's up to us not to background.
if [ "x$foreground" != "x" ]; then
es_parms="$es_parms -Des.foreground=yes"
exec "$JAVA" $JAVA_OPTS $ES_JAVA_OPTS $es_parms -Des.path.home="$ES_HOME" -cp "$ES_CLASSPATH" $props \
org.elasticsearch.bootstrap.ElasticSearch
execval=$?
else
# Startup ElasticSearch, background it, and write the pid.
exec "$JAVA" $JAVA_OPTS $ES_JAVA_OPTS $es_parms -Des.path.home="$ES_HOME" -cp "$ES_CLASSPATH" $props \
org.elasticsearch.bootstrap.ElasticSearch <&- &
execval=$?
[ ! -z "$pidpath" ] && printf '%d' $! > "$pidpath"
fi

return $execval
}

# Parse any command line options.
args=`getopt vfhp:D:X: "$@"`
eval set -- "$args"

while true; do
case $1 in
-v)
"$JAVA" $JAVA_OPTS $ES_JAVA_OPTS $es_parms -Des.path.home="$ES_HOME" -cp "$ES_CLASSPATH" $props \
org.elasticsearch.Version
exit 0
;;
-p)
pidfile="$2"
shift 2
;;
-f)
foreground="yes"
shift
;;
-h)
echo "Usage: $0 [-f] [-h] [-p pidfile]"
exit 0
;;
-D)
properties="$properties -D$2"
shift 2
;;
-X)
properties="$properties -X$2"
shift 2
;;
--)
shift
break
;;
*)
echo "Error parsing arguments!" >&2
exit 1
;;
esac
done

# Start up the service
launch_service "$pidfile" "$foreground" "$properties"

exit $?
@@ -0,0 +1,67 @@
#!/bin/sh

ES_CLASSPATH=$ES_CLASSPATH:$ES_HOME/lib/elasticsearch-0.20.6.jar:$ES_HOME/lib/*:$ES_HOME/lib/sigar/*

if [ "x$ES_MIN_MEM" = "x" ]; then
ES_MIN_MEM=256m
fi
if [ "x$ES_MAX_MEM" = "x" ]; then
ES_MAX_MEM=1g
fi
if [ "x$ES_HEAP_SIZE" != "x" ]; then
ES_MIN_MEM=$ES_HEAP_SIZE
ES_MAX_MEM=$ES_HEAP_SIZE
fi

# min and max heap sizes should be set to the same value to avoid
# stop-the-world GC pauses during resize, and so that we can lock the
# heap in memory on startup to prevent any of it from being swapped
# out.
JAVA_OPTS="$JAVA_OPTS -Xms${ES_MIN_MEM}"
JAVA_OPTS="$JAVA_OPTS -Xmx${ES_MAX_MEM}"

# new generation
if [ "x$ES_HEAP_NEWSIZE" != "x" ]; then
JAVA_OPTS="$JAVA_OPTS -Xmn${ES_HEAP_NEWSIZE}"
fi

# max direct memory
if [ "x$ES_DIRECT_SIZE" != "x" ]; then
JAVA_OPTS="$JAVA_OPTS -XX:MaxDirectMemorySize=${ES_DIRECT_SIZE}"
fi

# reduce the per-thread stack size
JAVA_OPTS="$JAVA_OPTS -Xss256k"

# set to headless, just in case
JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true"

# Force the JVM to use IPv4 stack
if [ "x$ES_USE_IPV4" != "x" ]; then
JAVA_OPTS="$JAVA_OPTS -Djava.net.preferIPv4Stack=true"
fi

JAVA_OPTS="$JAVA_OPTS -XX:+UseParNewGC"
JAVA_OPTS="$JAVA_OPTS -XX:+UseConcMarkSweepGC"

JAVA_OPTS="$JAVA_OPTS -XX:CMSInitiatingOccupancyFraction=75"
JAVA_OPTS="$JAVA_OPTS -XX:+UseCMSInitiatingOccupancyOnly"

# When running under Java 7
# JAVA_OPTS="$JAVA_OPTS -XX:+UseCondCardMark"

# GC logging options
if [ "x$ES_USE_GC_LOGGING" != "x" ]; then
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCTimeStamps"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintClassHistogram"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintTenuringDistribution"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCApplicationStoppedTime"
JAVA_OPTS="$JAVA_OPTS -Xloggc:/var/log/elasticsearch/gc.log"
fi

# Causes the JVM to dump its heap on OutOfMemory.
JAVA_OPTS="$JAVA_OPTS -XX:+HeapDumpOnOutOfMemoryError"
# The path to the heap dump location, note directory must exists and have enough
# space for a full heap dump.
#JAVA_OPTS="$JAVA_OPTS -XX:HeapDumpPath=$ES_HOME/logs/heapdump.hprof"
@@ -0,0 +1,31 @@
#!/bin/sh

CDPATH=""
SCRIPT="$0"

# SCRIPT may be an arbitrarily deep series of symlinks. Loop until we have the concrete path.
while [ -h "$SCRIPT" ] ; do
ls=`ls -ld "$SCRIPT"`
# Drop everything prior to ->
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
SCRIPT="$link"
else
SCRIPT=`dirname "$SCRIPT"`/"$link"
fi
done

# determine elasticsearch home
ES_HOME=`dirname "$SCRIPT"`/..

# make ELASTICSEARCH_HOME absolute
ES_HOME=`cd "$ES_HOME"; pwd`


if [ -x "$JAVA_HOME/bin/java" ]; then
JAVA=$JAVA_HOME/bin/java
else
JAVA=`which java`
fi

exec $JAVA $JAVA_OPTS -Xmx64m -Xms16m -Delasticsearch -Des.path.home="$ES_HOME" -cp "$ES_HOME/lib/*" org.elasticsearch.plugins.PluginManager $*