157 |
158 |
346 | {% endblock %}
347 |
--------------------------------------------------------------------------------
/shp2svg/views.py:
--------------------------------------------------------------------------------
1 | import math
2 | import base64
3 | import zipfile
4 | from zipfile import ZipFile
5 | from django.conf import settings
6 | from django.core.cache import cache
7 | from django.shortcuts import render
8 | from django.shortcuts import redirect
9 | from django.contrib.gis.gdal import *
10 | from django.template import RequestContext
11 | from django.views.generic.base import View
12 | from django.contrib.sitemaps import Sitemap
13 | from django.utils import simplejson as json
14 | from django.core.urlresolvers import reverse
15 | from django.core.files.base import ContentFile
16 | from django.template.loader import get_template
17 | from django.template.defaultfilters import slugify
18 | from shp2svg.models import Shape, ShapefileContainer
19 | from django.contrib.gis.geos import MultiPolygon, Polygon
20 | from django.http import Http404, HttpResponse, HttpResponseBadRequest
21 |
22 | #
23 | # Sitemaps
24 | #
25 |
26 | class ShapefileContainerSitemap(Sitemap):
27 | changefreq = "daily"
28 |
29 | def items(self):
30 | return ShapefileContainer.objects.all()
31 |
32 |
33 | class Sitemap(Sitemap):
34 | def __init__(self, names):
35 | self.names = names
36 |
37 | def items(self):
38 | return self.names
39 |
40 | def changefreq(self, obj):
41 | return 'daily'
42 |
43 | def location(self, obj):
44 | return reverse(obj)
45 |
46 | #
47 | # Content
48 | #
49 |
50 | def index(request):
51 | context = {
52 | 'shapefiles': ShapefileContainer.objects.all()
53 | }
54 | return render(request, 'index.html', context)
55 |
56 | def shapefile_detail(request, slug):
57 | try:
58 | shapefile = ShapefileContainer.objects.get(slug=slug)
59 | except ShapefileContainer.DoesNotExist:
60 | raise Http404
61 |
62 | ds = DataSource(shapefile.shp.path)
63 | layer = ds[0]
64 | context = {
65 | 'name': shapefile.name,
66 | 'slug': shapefile.slug,
67 | 'fields': layer.fields,
68 | 'source': shapefile.source,
69 | }
70 | return render(request, 'shapefilecontainer_detail.html', context)
71 |
72 | def upload_shapefile(request):
73 | if request.method == 'POST':
74 | name = request.POST.get('name')
75 | # Check to see if we already have an object with that name
76 | try:
77 | ShapefileContainer.objects.get(slug=slugify(name))
78 | return HttpResponseBadRequest("The name you chose is already taken.")
79 | except ShapefileContainer.DoesNotExist:
80 | pass
81 |
82 | # Do we have a zip file?
83 | z = request.FILES.get('zipfile', False)
84 | if z:
85 | if not zipfile.is_zipfile(z):
86 | return HttpResponseBadRequest("You have uploaded an invalid zip file.")
87 | zipped = ZipFile(z)
88 | filenames = [i.filename for i in zipped.filelist]
89 | dbf, prj, shp, shx = False, False, False, False
90 | for i in filenames:
91 | if '.dbf' in i.lower()[-4:]:
92 | dbf = ContentFile(zipped.read(i))
93 | elif '.prj' in i.lower()[-4:]:
94 | prj = ContentFile(zipped.read(i))
95 | elif '.shp' in i.lower()[-4:]:
96 | shp = ContentFile(zipped.read(i))
97 | elif '.shx' in i.lower()[-4:]:
98 | shx = ContentFile(zipped.read(i))
99 | # make our new container object
100 | if dbf and prj and shp and shx:
101 | new_shapefile = ShapefileContainer.objects.create(
102 | name=name,
103 | slug=slugify(name),
104 | )
105 | new_shapefile.dbf.save('dbf', dbf)
106 | new_shapefile.prj.save('prj', prj)
107 | new_shapefile.shp.save('shp', shp)
108 | new_shapefile.shx.save('shx', shx)
109 | else:
110 | return HttpResponseBadRequest("Your zip file must contain a .dbf, a .prj, a .shp and a .shx file.")
111 | else:
112 | # Make the new shape container from the individually uploaded files
113 | new_shapefile = ShapefileContainer.objects.create(
114 | name=name,
115 | slug=slugify(name),
116 | dbf=request.FILES.get('dbf'),
117 | prj=request.FILES.get('prj'),
118 | shp=request.FILES.get('shp'),
119 | shx=request.FILES.get('shx'),
120 | )
121 | source = request.POST.get('source', False)
122 | if source:
123 | new_shapefile.source = source
124 | new_shapefile.save()
125 | # See if we can import the shapefile.
126 | try:
127 | ds = DataSource(new_shapefile.shp.path)
128 | except:
129 | new_shapefile.delete()
130 | return HttpResponseBadRequest("There was a problem processing your shapefile.")
131 |
132 | layer = ds[0]
133 | attribute_fields = layer.fields
134 | for feature in layer:
135 | if feature.geom.geom_type in ['Polygon', 'MultiPolygon']:
136 | # Grab a dict of all the attributes
137 | attribute_dict = dict( (attr, str(feature[attr].value).decode('latin-1')) for attr in attribute_fields )
138 | # convert to multipolygon if necessary
139 | if feature.geom.geom_type == 'Polygon':
140 | mp = MultiPolygon(feature.geom.geos)
141 | else:
142 | mp = feature.geom.geos
143 | # load in the shape
144 | try:
145 | shape = Shape.objects.create(
146 | poly = mp,
147 | attributes = json.dumps(attribute_dict),
148 | shapefile = new_shapefile,
149 | )
150 | except:
151 | return HttpResponseBadRequest("There was a problem processing your shapefile.")
152 | else:
153 | continue
154 |
155 | data = {
156 | 'name': new_shapefile.name,
157 | 'slug': new_shapefile.slug,
158 | 'fields': attribute_fields,
159 | }
160 | return HttpResponse(json.dumps(data), content_type='text/html')
161 |
162 |
163 | class SVGResponseMixin(object):
164 | """
165 | A mixin that can be used to render an SVG response.
166 | """
167 | def render_to_response(self, context, **response_kwargs):
168 | """
169 | Returns a CSV file response, transforming 'context' to make the payload.
170 | """
171 | template = get_template('svg.html')
172 | context = RequestContext(self.request, context)
173 | svg = template.render(context)
174 | response = HttpResponse(svg, mimetype='image/svg+xml')
175 | response['Content-Disposition'] = 'attachment; filename=shp2svg.svg'
176 | return response
177 |
178 |
179 | class JSONResponseMixin(object):
180 | """
181 | A mixin for rendering a JSON as an AJAX response. Where the 'JSON' is actually
182 | sent as a text/html mimetype to avoid an awkward bug in IE.
183 | """
184 | def render_to_response(self, context, **response_kwargs):
185 | return HttpResponse(json.dumps(context), content_type='text/html')
186 |
187 |
188 | class GenerateSVG(SVGResponseMixin, JSONResponseMixin, View):
189 |
190 | def translate_coords(self, coord_list, extent):
191 | """
192 | Takes a list of coordinates and translates them to [0, 0]
193 | """
194 | x_min = extent[0]
195 | y_min = extent[1]
196 | y_translated_max = abs(extent[3] - extent[1])
197 | translated_coords = []
198 | for i in coord_list:
199 | new_coords = (i[0] - x_min, y_translated_max - (i[1] - y_min))
200 | translated_coords.append(new_coords)
201 | return translated_coords
202 |
203 | def coords_2_path(self, coord_list):
204 | """
205 | Takes a list of coordinates and returns an SVG path
206 | """
207 | if len(coord_list) == 1:
208 | path = 'M%s,%sZ' % (coord_list[0][0], coord_list[0][1])
209 | else:
210 | path = 'M%s,%s' % (coord_list[0][0], coord_list[0][1])
211 | for i in coord_list[1:]:
212 | path += 'L%s,%s' % (i[0], i[1])
213 | path += 'Z'
214 | return path.replace('-0.0', '0').replace('0.0', '0').replace('.0', '')
215 |
216 | def get_cache_key(self, obj, srid):
217 | """
218 | Create a unique cache key for the projected geoqueryset
219 | using the object slug and SRID
220 | """
221 | id_string = '&'.join([obj.slug, str(srid)])
222 | obj_hash = base64.b64encode(id_string)
223 | return 'shp2svg:queryset|%s' % obj_hash
224 |
225 | def get(self, request, *args, **kwargs):
226 | self.format = self.request.GET.get('format', 'json')
227 | slug = self.request.GET.get('slug')
228 | try:
229 | shapefile = ShapefileContainer.objects.get(slug=slug)
230 | except ShapefileContainer.DoesNotExist:
231 | raise Http404
232 |
233 | translate = [0, 0]
234 | # some validation on the user input
235 | invalid_int_response = HttpResponseBadRequest("Please enter a valid integer.")
236 |
237 | if self.request.GET.get('translate_x'):
238 | try:
239 | translate[0] = int(self.request.GET.get('translate_x'))
240 | except ValueError:
241 | return invalid_int_response
242 |
243 | if self.request.GET.get('translate_y'):
244 | try:
245 | translate[1] = int(self.request.GET.get('translate_y'))
246 | except ValueError:
247 | return invalid_int_response
248 |
249 | try:
250 | max_size = int(self.request.GET.get('max_size'))
251 | srid = int(self.request.GET.get('srid'))
252 | except ValueError:
253 | return invalid_int_response
254 |
255 | key = self.request.GET.get('key')
256 | centroid = self.request.GET.get('centroid', False)
257 | if centroid == 'on':
258 | centroid = True
259 |
260 | # get a projected geoqueryset
261 | cache_key = self.get_cache_key(shapefile, srid)
262 | projected_shapes = cache.get(cache_key, None)
263 | if not projected_shapes:
264 | projected_shapes = shapefile.get_projected_shapes(srid)
265 | cache.set(cache_key, projected_shapes)
266 |
267 | # get the projected extent of the geoqueryset
268 | x_coords = []
269 | y_coords = []
270 | # Wrap this in a try/except to return any errors we hit with the projection
271 | try:
272 | for i in projected_shapes:
273 | coords = i.poly.extent
274 | x_coords.append(coords[0])
275 | x_coords.append(coords[2])
276 | y_coords.append(coords[1])
277 | y_coords.append(coords[3])
278 | except:
279 | return HttpResponseBadRequest("There was a problem projecting your shapefile. Please try a different SRID.")
280 |
281 | extent = (min(x_coords), min(y_coords), max(x_coords), max(y_coords))
282 |
283 | # get a constant to scale the coords to the provided max_size
284 | max_translated_x = abs(extent[2] - extent[0])
285 | max_translated_y = abs(extent[3] - extent[1])
286 |
287 | if max_translated_x > max_translated_y:
288 | scale_factor = max_size / max_translated_x
289 | else:
290 | scale_factor = max_size / max_translated_y
291 |
292 | # Determine our new max X and Y values
293 | max_coords = [int(math.ceil(max_translated_x * scale_factor)), int(math.ceil(max_translated_y * scale_factor))]
294 |
295 | # generate all the paths
296 | paths = {}
297 | for i in projected_shapes:
298 | # load in the attribute dict
299 | attrs = json.loads(i.attributes)
300 | k = attrs.get(key)
301 | # First grab the coordinates to play with
302 | coords = i.get_extracted_coords()
303 | # Loop through each set and translate them
304 | translated_coords = []
305 | for c in coords:
306 | translated_coords.append(self.translate_coords(c, extent))
307 |
308 | # Then loop through our translated coords and scale them
309 | scaled_coords = []
310 | for t in translated_coords:
311 | scaled_list = []
312 | for coord_set in t:
313 | scaled_set = (format(( coord_set[0] * scale_factor) + translate[0], '.1f'), format(( coord_set[1] * scale_factor) + translate[1], '.1f'))
314 | scaled_list.append(scaled_set)
315 | scaled_coords.append(scaled_list)
316 |
317 | # Now to grab a translated/scaled centroid for each shape
318 | if centroid:
319 | centroid = i.poly.centroid.coords
320 | translated_centroid = self.translate_coords([centroid], extent)
321 | translated_centroid = translated_centroid[0]
322 | scaled_centroid = [int(translated_centroid[0] * scale_factor) + translate[0], int(translated_centroid[1] * scale_factor) + translate[1]]
323 |
324 | path = ''
325 | for i in scaled_coords:
326 | path += self.coords_2_path(i)
327 |
328 | paths[k] = {
329 | 'path': path,
330 | 'centroid': scaled_centroid,
331 | }
332 | else:
333 | path = ''
334 | for i in scaled_coords:
335 | path += self.coords_2_path(i)
336 |
337 | paths[k] = path
338 |
339 | context = {
340 | 'paths': paths,
341 | 'url': self.request.get_full_path(),
342 | 'centroid': centroid,
343 | 'max_coords': [max_coords[0] + translate[0], max_coords[1] + translate[1]],
344 | }
345 | return self.render_to_response(context)
346 |
347 | def render_to_response(self, context, **response_kwargs):
348 | """
349 | Figures out what type of response is necessary and pulls the trigger.
350 | """
351 | if self.format == 'json':
352 | return JSONResponseMixin.render_to_response(self, context)
353 | elif self.format == 'svg':
354 | return SVGResponseMixin.render_to_response(self, context)
355 | else:
356 | return Http404
357 |
358 |
--------------------------------------------------------------------------------
/templates/static/css/bootstrap-responsive.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap Responsive v2.2.1
3 | *
4 | * Copyright 2012 Twitter, Inc
5 | * Licensed under the Apache License v2.0
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | * Designed and built with all the love in the world @twitter by @mdo and @fat.
9 | */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}}
10 |
--------------------------------------------------------------------------------
/templates/static/js/json2.js:
--------------------------------------------------------------------------------
1 | /*
2 | json2.js
3 | 2012-10-08
4 |
5 | Public Domain.
6 |
7 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8 |
9 | See http://www.JSON.org/js.html
10 |
11 |
12 | This code should be minified before deployment.
13 | See http://javascript.crockford.com/jsmin.html
14 |
15 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
16 | NOT CONTROL.
17 |
18 |
19 | This file creates a global JSON object containing two methods: stringify
20 | and parse.
21 |
22 | JSON.stringify(value, replacer, space)
23 | value any JavaScript value, usually an object or array.
24 |
25 | replacer an optional parameter that determines how object
26 | values are stringified for objects. It can be a
27 | function or an array of strings.
28 |
29 | space an optional parameter that specifies the indentation
30 | of nested structures. If it is omitted, the text will
31 | be packed without extra whitespace. If it is a number,
32 | it will specify the number of spaces to indent at each
33 | level. If it is a string (such as '\t' or ' '),
34 | it contains the characters used to indent at each level.
35 |
36 | This method produces a JSON text from a JavaScript value.
37 |
38 | When an object value is found, if the object contains a toJSON
39 | method, its toJSON method will be called and the result will be
40 | stringified. A toJSON method does not serialize: it returns the
41 | value represented by the name/value pair that should be serialized,
42 | or undefined if nothing should be serialized. The toJSON method
43 | will be passed the key associated with the value, and this will be
44 | bound to the value
45 |
46 | For example, this would serialize Dates as ISO strings.
47 |
48 | Date.prototype.toJSON = function (key) {
49 | function f(n) {
50 | // Format integers to have at least two digits.
51 | return n < 10 ? '0' + n : n;
52 | }
53 |
54 | return this.getUTCFullYear() + '-' +
55 | f(this.getUTCMonth() + 1) + '-' +
56 | f(this.getUTCDate()) + 'T' +
57 | f(this.getUTCHours()) + ':' +
58 | f(this.getUTCMinutes()) + ':' +
59 | f(this.getUTCSeconds()) + 'Z';
60 | };
61 |
62 | You can provide an optional replacer method. It will be passed the
63 | key and value of each member, with this bound to the containing
64 | object. The value that is returned from your method will be
65 | serialized. If your method returns undefined, then the member will
66 | be excluded from the serialization.
67 |
68 | If the replacer parameter is an array of strings, then it will be
69 | used to select the members to be serialized. It filters the results
70 | such that only members with keys listed in the replacer array are
71 | stringified.
72 |
73 | Values that do not have JSON representations, such as undefined or
74 | functions, will not be serialized. Such values in objects will be
75 | dropped; in arrays they will be replaced with null. You can use
76 | a replacer function to replace those with JSON values.
77 | JSON.stringify(undefined) returns undefined.
78 |
79 | The optional space parameter produces a stringification of the
80 | value that is filled with line breaks and indentation to make it
81 | easier to read.
82 |
83 | If the space parameter is a non-empty string, then that string will
84 | be used for indentation. If the space parameter is a number, then
85 | the indentation will be that many spaces.
86 |
87 | Example:
88 |
89 | text = JSON.stringify(['e', {pluribus: 'unum'}]);
90 | // text is '["e",{"pluribus":"unum"}]'
91 |
92 |
93 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
94 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
95 |
96 | text = JSON.stringify([new Date()], function (key, value) {
97 | return this[key] instanceof Date ?
98 | 'Date(' + this[key] + ')' : value;
99 | });
100 | // text is '["Date(---current time---)"]'
101 |
102 |
103 | JSON.parse(text, reviver)
104 | This method parses a JSON text to produce an object or array.
105 | It can throw a SyntaxError exception.
106 |
107 | The optional reviver parameter is a function that can filter and
108 | transform the results. It receives each of the keys and values,
109 | and its return value is used instead of the original value.
110 | If it returns what it received, then the structure is not modified.
111 | If it returns undefined then the member is deleted.
112 |
113 | Example:
114 |
115 | // Parse the text. Values that look like ISO date strings will
116 | // be converted to Date objects.
117 |
118 | myData = JSON.parse(text, function (key, value) {
119 | var a;
120 | if (typeof value === 'string') {
121 | a =
122 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
123 | if (a) {
124 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
125 | +a[5], +a[6]));
126 | }
127 | }
128 | return value;
129 | });
130 |
131 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
132 | var d;
133 | if (typeof value === 'string' &&
134 | value.slice(0, 5) === 'Date(' &&
135 | value.slice(-1) === ')') {
136 | d = new Date(value.slice(5, -1));
137 | if (d) {
138 | return d;
139 | }
140 | }
141 | return value;
142 | });
143 |
144 |
145 | This is a reference implementation. You are free to copy, modify, or
146 | redistribute.
147 | */
148 |
149 | /*jslint evil: true, regexp: true */
150 |
151 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
152 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
153 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
154 | lastIndex, length, parse, prototype, push, replace, slice, stringify,
155 | test, toJSON, toString, valueOf
156 | */
157 |
158 |
159 | // Create a JSON object only if one does not already exist. We create the
160 | // methods in a closure to avoid creating global variables.
161 |
162 | if (typeof JSON !== 'object') {
163 | JSON = {};
164 | }
165 |
166 | (function () {
167 | 'use strict';
168 |
169 | function f(n) {
170 | // Format integers to have at least two digits.
171 | return n < 10 ? '0' + n : n;
172 | }
173 |
174 | if (typeof Date.prototype.toJSON !== 'function') {
175 |
176 | Date.prototype.toJSON = function (key) {
177 |
178 | return isFinite(this.valueOf())
179 | ? this.getUTCFullYear() + '-' +
180 | f(this.getUTCMonth() + 1) + '-' +
181 | f(this.getUTCDate()) + 'T' +
182 | f(this.getUTCHours()) + ':' +
183 | f(this.getUTCMinutes()) + ':' +
184 | f(this.getUTCSeconds()) + 'Z'
185 | : null;
186 | };
187 |
188 | String.prototype.toJSON =
189 | Number.prototype.toJSON =
190 | Boolean.prototype.toJSON = function (key) {
191 | return this.valueOf();
192 | };
193 | }
194 |
195 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
196 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
197 | gap,
198 | indent,
199 | meta = { // table of character substitutions
200 | '\b': '\\b',
201 | '\t': '\\t',
202 | '\n': '\\n',
203 | '\f': '\\f',
204 | '\r': '\\r',
205 | '"' : '\\"',
206 | '\\': '\\\\'
207 | },
208 | rep;
209 |
210 |
211 | function quote(string) {
212 |
213 | // If the string contains no control characters, no quote characters, and no
214 | // backslash characters, then we can safely slap some quotes around it.
215 | // Otherwise we must also replace the offending characters with safe escape
216 | // sequences.
217 |
218 | escapable.lastIndex = 0;
219 | return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
220 | var c = meta[a];
221 | return typeof c === 'string'
222 | ? c
223 | : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
224 | }) + '"' : '"' + string + '"';
225 | }
226 |
227 |
228 | function str(key, holder) {
229 |
230 | // Produce a string from holder[key].
231 |
232 | var i, // The loop counter.
233 | k, // The member key.
234 | v, // The member value.
235 | length,
236 | mind = gap,
237 | partial,
238 | value = holder[key];
239 |
240 | // If the value has a toJSON method, call it to obtain a replacement value.
241 |
242 | if (value && typeof value === 'object' &&
243 | typeof value.toJSON === 'function') {
244 | value = value.toJSON(key);
245 | }
246 |
247 | // If we were called with a replacer function, then call the replacer to
248 | // obtain a replacement value.
249 |
250 | if (typeof rep === 'function') {
251 | value = rep.call(holder, key, value);
252 | }
253 |
254 | // What happens next depends on the value's type.
255 |
256 | switch (typeof value) {
257 | case 'string':
258 | return quote(value);
259 |
260 | case 'number':
261 |
262 | // JSON numbers must be finite. Encode non-finite numbers as null.
263 |
264 | return isFinite(value) ? String(value) : 'null';
265 |
266 | case 'boolean':
267 | case 'null':
268 |
269 | // If the value is a boolean or null, convert it to a string. Note:
270 | // typeof null does not produce 'null'. The case is included here in
271 | // the remote chance that this gets fixed someday.
272 |
273 | return String(value);
274 |
275 | // If the type is 'object', we might be dealing with an object or an array or
276 | // null.
277 |
278 | case 'object':
279 |
280 | // Due to a specification blunder in ECMAScript, typeof null is 'object',
281 | // so watch out for that case.
282 |
283 | if (!value) {
284 | return 'null';
285 | }
286 |
287 | // Make an array to hold the partial results of stringifying this object value.
288 |
289 | gap += indent;
290 | partial = [];
291 |
292 | // Is the value an array?
293 |
294 | if (Object.prototype.toString.apply(value) === '[object Array]') {
295 |
296 | // The value is an array. Stringify every element. Use null as a placeholder
297 | // for non-JSON values.
298 |
299 | length = value.length;
300 | for (i = 0; i < length; i += 1) {
301 | partial[i] = str(i, value) || 'null';
302 | }
303 |
304 | // Join all of the elements together, separated with commas, and wrap them in
305 | // brackets.
306 |
307 | v = partial.length === 0
308 | ? '[]'
309 | : gap
310 | ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
311 | : '[' + partial.join(',') + ']';
312 | gap = mind;
313 | return v;
314 | }
315 |
316 | // If the replacer is an array, use it to select the members to be stringified.
317 |
318 | if (rep && typeof rep === 'object') {
319 | length = rep.length;
320 | for (i = 0; i < length; i += 1) {
321 | if (typeof rep[i] === 'string') {
322 | k = rep[i];
323 | v = str(k, value);
324 | if (v) {
325 | partial.push(quote(k) + (gap ? ': ' : ':') + v);
326 | }
327 | }
328 | }
329 | } else {
330 |
331 | // Otherwise, iterate through all of the keys in the object.
332 |
333 | for (k in value) {
334 | if (Object.prototype.hasOwnProperty.call(value, k)) {
335 | v = str(k, value);
336 | if (v) {
337 | partial.push(quote(k) + (gap ? ': ' : ':') + v);
338 | }
339 | }
340 | }
341 | }
342 |
343 | // Join all of the member texts together, separated with commas,
344 | // and wrap them in braces.
345 |
346 | v = partial.length === 0
347 | ? '{}'
348 | : gap
349 | ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
350 | : '{' + partial.join(',') + '}';
351 | gap = mind;
352 | return v;
353 | }
354 | }
355 |
356 | // If the JSON object does not yet have a stringify method, give it one.
357 |
358 | if (typeof JSON.stringify !== 'function') {
359 | JSON.stringify = function (value, replacer, space) {
360 |
361 | // The stringify method takes a value and an optional replacer, and an optional
362 | // space parameter, and returns a JSON text. The replacer can be a function
363 | // that can replace values, or an array of strings that will select the keys.
364 | // A default replacer method can be provided. Use of the space parameter can
365 | // produce text that is more easily readable.
366 |
367 | var i;
368 | gap = '';
369 | indent = '';
370 |
371 | // If the space parameter is a number, make an indent string containing that
372 | // many spaces.
373 |
374 | if (typeof space === 'number') {
375 | for (i = 0; i < space; i += 1) {
376 | indent += ' ';
377 | }
378 |
379 | // If the space parameter is a string, it will be used as the indent string.
380 |
381 | } else if (typeof space === 'string') {
382 | indent = space;
383 | }
384 |
385 | // If there is a replacer, it must be a function or an array.
386 | // Otherwise, throw an error.
387 |
388 | rep = replacer;
389 | if (replacer && typeof replacer !== 'function' &&
390 | (typeof replacer !== 'object' ||
391 | typeof replacer.length !== 'number')) {
392 | throw new Error('JSON.stringify');
393 | }
394 |
395 | // Make a fake root object containing our value under the key of ''.
396 | // Return the result of stringifying the value.
397 |
398 | return str('', {'': value});
399 | };
400 | }
401 |
402 |
403 | // If the JSON object does not yet have a parse method, give it one.
404 |
405 | if (typeof JSON.parse !== 'function') {
406 | JSON.parse = function (text, reviver) {
407 |
408 | // The parse method takes a text and an optional reviver function, and returns
409 | // a JavaScript value if the text is a valid JSON text.
410 |
411 | var j;
412 |
413 | function walk(holder, key) {
414 |
415 | // The walk method is used to recursively walk the resulting structure so
416 | // that modifications can be made.
417 |
418 | var k, v, value = holder[key];
419 | if (value && typeof value === 'object') {
420 | for (k in value) {
421 | if (Object.prototype.hasOwnProperty.call(value, k)) {
422 | v = walk(value, k);
423 | if (v !== undefined) {
424 | value[k] = v;
425 | } else {
426 | delete value[k];
427 | }
428 | }
429 | }
430 | }
431 | return reviver.call(holder, key, value);
432 | }
433 |
434 |
435 | // Parsing happens in four stages. In the first stage, we replace certain
436 | // Unicode characters with escape sequences. JavaScript handles many characters
437 | // incorrectly, either silently deleting them, or treating them as line endings.
438 |
439 | text = String(text);
440 | cx.lastIndex = 0;
441 | if (cx.test(text)) {
442 | text = text.replace(cx, function (a) {
443 | return '\\u' +
444 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
445 | });
446 | }
447 |
448 | // In the second stage, we run the text against regular expressions that look
449 | // for non-JSON patterns. We are especially concerned with '()' and 'new'
450 | // because they can cause invocation, and '=' because it can cause mutation.
451 | // But just to be safe, we want to reject all unexpected forms.
452 |
453 | // We split the second stage into 4 regexp operations in order to work around
454 | // crippling inefficiencies in IE's and Safari's regexp engines. First we
455 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
456 | // replace all simple value tokens with ']' characters. Third, we delete all
457 | // open brackets that follow a colon or comma or that begin the text. Finally,
458 | // we look to see that the remaining characters are only whitespace or ']' or
459 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
460 |
461 | if (/^[\],:{}\s]*$/
462 | .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
463 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
464 | .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
465 |
466 | // In the third stage we use the eval function to compile the text into a
467 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
468 | // in JavaScript: it can begin a block or an object literal. We wrap the text
469 | // in parens to eliminate the ambiguity.
470 |
471 | j = eval('(' + text + ')');
472 |
473 | // In the optional fourth stage, we recursively walk the new structure, passing
474 | // each name/value pair to a reviver function for possible transformation.
475 |
476 | return typeof reviver === 'function'
477 | ? walk({'': j}, '')
478 | : j;
479 | }
480 |
481 | // If the text is not JSON parseable, then a SyntaxError is thrown.
482 |
483 | throw new SyntaxError('JSON.parse');
484 | };
485 | }
486 | }());
487 |
--------------------------------------------------------------------------------
/templates/static/js/bootstrap.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap.js by @fat & @mdo
3 | * Copyright 2012 Twitter, Inc.
4 | * http://www.apache.org/licenses/LICENSE-2.0.txt
5 | */
6 | !function(e){"use strict";e(function(){e.support.transition=function(){var e=function(){var e=document.createElement("bootstrap"),t={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},n;for(n in t)if(e.style[n]!==undefined)return t[n]}();return e&&{end:e}}()})}(window.jQuery),!function(e){"use strict";var t='[data-dismiss="alert"]',n=function(n){e(n).on("click",t,this.close)};n.prototype.close=function(t){function s(){i.trigger("closed").remove()}var n=e(this),r=n.attr("data-target"),i;r||(r=n.attr("href"),r=r&&r.replace(/.*(?=#[^\s]*$)/,"")),i=e(r),t&&t.preventDefault(),i.length||(i=n.hasClass("alert")?n:n.parent()),i.trigger(t=e.Event("close"));if(t.isDefaultPrevented())return;i.removeClass("in"),e.support.transition&&i.hasClass("fade")?i.on(e.support.transition.end,s):s()},e.fn.alert=function(t){return this.each(function(){var r=e(this),i=r.data("alert");i||r.data("alert",i=new n(this)),typeof t=="string"&&i[t].call(r)})},e.fn.alert.Constructor=n,e(document).on("click.alert.data-api",t,n.prototype.close)}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.button.defaults,n)};t.prototype.setState=function(e){var t="disabled",n=this.$element,r=n.data(),i=n.is("input")?"val":"html";e+="Text",r.resetText||n.data("resetText",n[i]()),n[i](r[e]||this.options[e]),setTimeout(function(){e=="loadingText"?n.addClass(t).attr(t,t):n.removeClass(t).removeAttr(t)},0)},t.prototype.toggle=function(){var e=this.$element.closest('[data-toggle="buttons-radio"]');e&&e.find(".active").removeClass("active"),this.$element.toggleClass("active")},e.fn.button=function(n){return this.each(function(){var r=e(this),i=r.data("button"),s=typeof n=="object"&&n;i||r.data("button",i=new t(this,s)),n=="toggle"?i.toggle():n&&i.setState(n)})},e.fn.button.defaults={loadingText:"loading..."},e.fn.button.Constructor=t,e(document).on("click.button.data-api","[data-toggle^=button]",function(t){var n=e(t.target);n.hasClass("btn")||(n=n.closest(".btn")),n.button("toggle")})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=n,this.options.slide&&this.slide(this.options.slide),this.options.pause=="hover"&&this.$element.on("mouseenter",e.proxy(this.pause,this)).on("mouseleave",e.proxy(this.cycle,this))};t.prototype={cycle:function(t){return t||(this.paused=!1),this.options.interval&&!this.paused&&(this.interval=setInterval(e.proxy(this.next,this),this.options.interval)),this},to:function(t){var n=this.$element.find(".item.active"),r=n.parent().children(),i=r.index(n),s=this;if(t>r.length-1||t<0)return;return this.sliding?this.$element.one("slid",function(){s.to(t)}):i==t?this.pause().cycle():this.slide(t>i?"next":"prev",e(r[t]))},pause:function(t){return t||(this.paused=!0),this.$element.find(".next, .prev").length&&e.support.transition.end&&(this.$element.trigger(e.support.transition.end),this.cycle()),clearInterval(this.interval),this.interval=null,this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(t,n){var r=this.$element.find(".item.active"),i=n||r[t](),s=this.interval,o=t=="next"?"left":"right",u=t=="next"?"first":"last",a=this,f;this.sliding=!0,s&&this.pause(),i=i.length?i:this.$element.find(".item")[u](),f=e.Event("slide",{relatedTarget:i[0]});if(i.hasClass("active"))return;if(e.support.transition&&this.$element.hasClass("slide")){this.$element.trigger(f);if(f.isDefaultPrevented())return;i.addClass(t),i[0].offsetWidth,r.addClass(o),i.addClass(o),this.$element.one(e.support.transition.end,function(){i.removeClass([t,o].join(" ")).addClass("active"),r.removeClass(["active",o].join(" ")),a.sliding=!1,setTimeout(function(){a.$element.trigger("slid")},0)})}else{this.$element.trigger(f);if(f.isDefaultPrevented())return;r.removeClass("active"),i.addClass("active"),this.sliding=!1,this.$element.trigger("slid")}return s&&this.cycle(),this}},e.fn.carousel=function(n){return this.each(function(){var r=e(this),i=r.data("carousel"),s=e.extend({},e.fn.carousel.defaults,typeof n=="object"&&n),o=typeof n=="string"?n:s.slide;i||r.data("carousel",i=new t(this,s)),typeof n=="number"?i.to(n):o?i[o]():s.interval&&i.cycle()})},e.fn.carousel.defaults={interval:5e3,pause:"hover"},e.fn.carousel.Constructor=t,e(document).on("click.carousel.data-api","[data-slide]",function(t){var n=e(this),r,i=e(n.attr("data-target")||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,"")),s=e.extend({},i.data(),n.data());i.carousel(s),t.preventDefault()})}(window.jQuery),!function(e){"use strict";var t=function(t,n){this.$element=e(t),this.options=e.extend({},e.fn.collapse.defaults,n),this.options.parent&&(this.$parent=e(this.options.parent)),this.options.toggle&&this.toggle()};t.prototype={constructor:t,dimension:function(){var e=this.$element.hasClass("width");return e?"width":"height"},show:function(){var t,n,r,i;if(this.transitioning)return;t=this.dimension(),n=e.camelCase(["scroll",t].join("-")),r=this.$parent&&this.$parent.find("> .accordion-group > .in");if(r&&r.length){i=r.data("collapse");if(i&&i.transitioning)return;r.collapse("hide"),i||r.data("collapse",null)}this.$element[t](0),this.transition("addClass",e.Event("show"),"shown"),e.support.transition&&this.$element[t](this.$element[0][n])},hide:function(){var t;if(this.transitioning)return;t=this.dimension(),this.reset(this.$element[t]()),this.transition("removeClass",e.Event("hide"),"hidden"),this.$element[t](0)},reset:function(e){var t=this.dimension();return this.$element.removeClass("collapse")[t](e||"auto")[0].offsetWidth,this.$element[e!==null?"addClass":"removeClass"]("collapse"),this},transition:function(t,n,r){var i=this,s=function(){n.type=="show"&&i.reset(),i.transitioning=0,i.$element.trigger(r)};this.$element.trigger(n);if(n.isDefaultPrevented())return;this.transitioning=1,this.$element[t]("in"),e.support.transition&&this.$element.hasClass("collapse")?this.$element.one(e.support.transition.end,s):s()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},e.fn.collapse=function(n){return this.each(function(){var r=e(this),i=r.data("collapse"),s=typeof n=="object"&&n;i||r.data("collapse",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.collapse.defaults={toggle:!0},e.fn.collapse.Constructor=t,e(document).on("click.collapse.data-api","[data-toggle=collapse]",function(t){var n=e(this),r,i=n.attr("data-target")||t.preventDefault()||(r=n.attr("href"))&&r.replace(/.*(?=#[^\s]+$)/,""),s=e(i).data("collapse")?"toggle":n.data();n[e(i).hasClass("in")?"addClass":"removeClass"]("collapsed"),e(i).collapse(s)})}(window.jQuery),!function(e){"use strict";function r(){e(t).each(function(){i(e(this)).removeClass("open")})}function i(t){var n=t.attr("data-target"),r;return n||(n=t.attr("href"),n=n&&/#/.test(n)&&n.replace(/.*(?=#[^\s]*$)/,"")),r=e(n),r.length||(r=t.parent()),r}var t="[data-toggle=dropdown]",n=function(t){var n=e(t).on("click.dropdown.data-api",this.toggle);e("html").on("click.dropdown.data-api",function(){n.parent().removeClass("open")})};n.prototype={constructor:n,toggle:function(t){var n=e(this),s,o;if(n.is(".disabled, :disabled"))return;return s=i(n),o=s.hasClass("open"),r(),o||(s.toggleClass("open"),n.focus()),!1},keydown:function(t){var n,r,s,o,u,a;if(!/(38|40|27)/.test(t.keyCode))return;n=e(this),t.preventDefault(),t.stopPropagation();if(n.is(".disabled, :disabled"))return;o=i(n),u=o.hasClass("open");if(!u||u&&t.keyCode==27)return n.click();r=e("[role=menu] li:not(.divider) a",o);if(!r.length)return;a=r.index(r.filter(":focus")),t.keyCode==38&&a>0&&a--,t.keyCode==40&&a').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?e.proxy(this.$element[0].focus,this.$element[0]):e.proxy(this.hide,this)),i&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),i?this.$backdrop.one(e.support.transition.end,t):t()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),e.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(e.support.transition.end,e.proxy(this.removeBackdrop,this)):this.removeBackdrop()):t&&t()}},e.fn.modal=function(n){return this.each(function(){var r=e(this),i=r.data("modal"),s=e.extend({},e.fn.modal.defaults,r.data(),typeof n=="object"&&n);i||r.data("modal",i=new t(this,s)),typeof n=="string"?i[n]():s.show&&i.show()})},e.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},e.fn.modal.Constructor=t,e(document).on("click.modal.data-api",'[data-toggle="modal"]',function(t){var n=e(this),r=n.attr("href"),i=e(n.attr("data-target")||r&&r.replace(/.*(?=#[^\s]+$)/,"")),s=i.data("modal")?"toggle":e.extend({remote:!/#/.test(r)&&r},i.data(),n.data());t.preventDefault(),i.modal(s).one("hide",function(){n.focus()})})}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("tooltip",e,t)};t.prototype={constructor:t,init:function(t,n,r){var i,s;this.type=t,this.$element=e(n),this.options=this.getOptions(r),this.enabled=!0,this.options.trigger=="click"?this.$element.on("click."+this.type,this.options.selector,e.proxy(this.toggle,this)):this.options.trigger!="manual"&&(i=this.options.trigger=="hover"?"mouseenter":"focus",s=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(i+"."+this.type,this.options.selector,e.proxy(this.enter,this)),this.$element.on(s+"."+this.type,this.options.selector,e.proxy(this.leave,this))),this.options.selector?this._options=e.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(t){return t=e.extend({},e.fn[this.type].defaults,t,this.$element.data()),t.delay&&typeof t.delay=="number"&&(t.delay={show:t.delay,hide:t.delay}),t},enter:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);if(!n.options.delay||!n.options.delay.show)return n.show();clearTimeout(this.timeout),n.hoverState="in",this.timeout=setTimeout(function(){n.hoverState=="in"&&n.show()},n.options.delay.show)},leave:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);this.timeout&&clearTimeout(this.timeout);if(!n.options.delay||!n.options.delay.hide)return n.hide();n.hoverState="out",this.timeout=setTimeout(function(){n.hoverState=="out"&&n.hide()},n.options.delay.hide)},show:function(){var e,t,n,r,i,s,o;if(this.hasContent()&&this.enabled){e=this.tip(),this.setContent(),this.options.animation&&e.addClass("fade"),s=typeof this.options.placement=="function"?this.options.placement.call(this,e[0],this.$element[0]):this.options.placement,t=/in/.test(s),e.detach().css({top:0,left:0,display:"block"}).insertAfter(this.$element),n=this.getPosition(t),r=e[0].offsetWidth,i=e[0].offsetHeight;switch(t?s.split(" ")[1]:s){case"bottom":o={top:n.top+n.height,left:n.left+n.width/2-r/2};break;case"top":o={top:n.top-i,left:n.left+n.width/2-r/2};break;case"left":o={top:n.top+n.height/2-i/2,left:n.left-r};break;case"right":o={top:n.top+n.height/2-i/2,left:n.left+n.width}}e.offset(o).addClass(s).addClass("in")}},setContent:function(){var e=this.tip(),t=this.getTitle();e.find(".tooltip-inner")[this.options.html?"html":"text"](t),e.removeClass("fade in top bottom left right")},hide:function(){function r(){var t=setTimeout(function(){n.off(e.support.transition.end).detach()},500);n.one(e.support.transition.end,function(){clearTimeout(t),n.detach()})}var t=this,n=this.tip();return n.removeClass("in"),e.support.transition&&this.$tip.hasClass("fade")?r():n.detach(),this},fixTitle:function(){var e=this.$element;(e.attr("title")||typeof e.attr("data-original-title")!="string")&&e.attr("data-original-title",e.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(t){return e.extend({},t?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-original-title")||(typeof n.title=="function"?n.title.call(t[0]):n.title),e},tip:function(){return this.$tip=this.$tip||e(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(t){var n=e(t.currentTarget)[this.type](this._options).data(this.type);n[n.tip().hasClass("in")?"hide":"show"]()},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}},e.fn.tooltip=function(n){return this.each(function(){var r=e(this),i=r.data("tooltip"),s=typeof n=="object"&&n;i||r.data("tooltip",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.tooltip.Constructor=t,e.fn.tooltip.defaults={animation:!0,placement:"top",selector:!1,template:'
',trigger:"hover",title:"",delay:0,html:!1}}(window.jQuery),!function(e){"use strict";var t=function(e,t){this.init("popover",e,t)};t.prototype=e.extend({},e.fn.tooltip.Constructor.prototype,{constructor:t,setContent:function(){var e=this.tip(),t=this.getTitle(),n=this.getContent();e.find(".popover-title")[this.options.html?"html":"text"](t),e.find(".popover-content > *")[this.options.html?"html":"text"](n),e.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var e,t=this.$element,n=this.options;return e=t.attr("data-content")||(typeof n.content=="function"?n.content.call(t[0]):n.content),e},tip:function(){return this.$tip||(this.$tip=e(this.options.template)),this.$tip},destroy:function(){this.hide().$element.off("."+this.type).removeData(this.type)}}),e.fn.popover=function(n){return this.each(function(){var r=e(this),i=r.data("popover"),s=typeof n=="object"&&n;i||r.data("popover",i=new t(this,s)),typeof n=="string"&&i[n]()})},e.fn.popover.Constructor=t,e.fn.popover.defaults=e.extend({},e.fn.tooltip.defaults,{placement:"right",trigger:"click",content:"",template:'