From: Maxious Date: Thu, 17 Jan 2013 05:29:34 +0000 Subject: better hourly record X-Git-Url: http://maxious.lambdacomplex.org/git/?p=scannr.git&a=commitdiff&h=cb7ea21cd1ad2c3d82bac661c439bab277d1d0d7 --- better hourly record --- --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,7 +2,6 @@ - --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -2,27 +2,55 @@ - - - - - - - + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - @@ -81,46 +109,19 @@ - - + + - + - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - + @@ -145,21 +146,21 @@ - @@ -187,8 +188,6 @@ - - @@ -209,16 +208,18 @@ + + - + + - + + - - + + + - + @@ -280,11 +284,11 @@ - + - + @@ -380,11 +384,6 @@ - - - - - @@ -402,35 +401,50 @@ - + + + + + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - + + + --- a/common.inc.php +++ b/common.inc.php @@ -57,12 +57,20 @@ + + + + + + + + + + + + +
+ +
+
+
+ +
+
+
+ +
+
+
+ +
+ + + + + + + + + + + + + + + + + --- a/db.sql +++ b/db.sql @@ -52,10 +52,11 @@ CREATE TABLE tgids ( tgid text NOT NULL, subfleet smallint, + alpha_tag text NOT NULL, mode character(1) DEFAULT 'D'::bpchar NOT NULL, - alpha_tag text NOT NULL, + description text, service_tag text, - category smallint + category text ); @@ -109,3 +110,4 @@ "channel" smallint NOT NULL, "calltype" text NOT NULL ); + --- a/generateHourlys.php +++ b/generateHourlys.php @@ -1,43 +1,46 @@ &1'; + if (!file_exists("hourly/" . $hfilename)) { + + $filenames = explode(",", $hourly['filenames']); + $cmd = "/usr/local/bin/ffmpeg -filter_complex concat=n=" . count($filenames) . ":v=0:a=1 -i data/" . implode(" -i data/", $filenames) . " -ar 8000 -ab 4.75k -ac 1 hourly/" . $hfilename . ' 2>&1'; //print_r($hourly); - exec ( $cmd,$output,$returncode ); - echo $cmd."
\n"; + exec($cmd, $output, $returncode); + echo $cmd . "
\n"; if ($returncode != 10) { - //print_r($output); + print_r($output); //die(); } else { - /* insert - "filename" text NOT NULL, - "files" text ARRAY NOT NULL, - "datetime" timestamp NOT NULL - */ - // delete wav files? can we link to times in a compilation? + $q = " insert into compilations (filename files datetime) ('" . $hfilename . "',{'" . implode("', '", $filenames) . "'},'" . strtottime($hourly['aday'] . ' +' . $hourly['ahour'] . " hours')") . "' "; + + foreach ($filenames as $filename) { + $q = "UPDATE recordings SET archived = '$hfilename' WHERE filename = '$filename' "; + } } } } -$sth = $conn->prepare("select tgid, extract(hour from call_timestamp) ahour, date_trunc('day', call_timestamp) aday, count(filename), array_to_string(array_agg(filename order by call_timestamp), ',') filenames from recordings group by tgid, ahour, aday order by aday DESC, ahour, tgid;"); + +$sth = $conn->prepare("SELECT tgid, EXTRACT(HOUR FROM call_timestamp) ahour, date_trunc('day', call_timestamp) aday, COUNT(filename), array_to_string(array_agg(filename ORDER BY call_timestamp), ',') filenames FROM recordings GROUP BY tgid, ahour, aday ORDER BY aday DESC, ahour, tgid;"); // TODO use tgid categories instead, tgid too specific $sth->execute(); $hourlies = $sth->fetchAll(PDO::FETCH_ASSOC); -foreach($hourlies as $hourly) { - //processHourly($hourly); +foreach ($hourlies as $hourly) { + processHourly($hourly); } -$sth = $conn->prepare("select 'hour' as tgid, extract(hour from call_timestamp) ahour, date_trunc('day', call_timestamp) aday, count(filename), array_to_string(array_agg(filename order by call_timestamp), ',') filenames from recordings group by ahour, aday order by aday DESC, ahour;"); +$sth = $conn->prepare("SELECT 'hour' AS tgid, EXTRACT(HOUR FROM call_timestamp) ahour, date_trunc('day', call_timestamp) aday, COUNT(filename), array_to_string(array_agg(filename ORDER BY call_timestamp), ',') filenames FROM recordings GROUP BY ahour, aday ORDER BY aday DESC, ahour;"); $sth->execute(); $hourlies = $sth->fetchAll(PDO::FETCH_ASSOC); -foreach($hourlies as $hourly) { +foreach ($hourlies as $hourly) { processHourly($hourly); } // delete uninteresting compilations + --- /dev/null +++ b/js/daterangepicker.js @@ -1,1 +1,609 @@ - +/** +* @version: 1.0.1 +* @author: Dan Grossman http://www.dangrossman.info/ +* @date: 2012-08-20 +* @copyright: Copyright (c) 2012 Dan Grossman. All rights reserved. +* @license: Licensed under Apache License v2.0. See http://www.apache.org/licenses/LICENSE-2.0 +* @website: http://www.improvely.com/ +*/ +!function ($) { + + var DateRangePicker = function (element, options, cb) { + var hasOptions = typeof options == 'object' + var localeObject; + + //state + this.startDate = Date.create('today'); + this.endDate = Date.create('today'); + this.minDate = false; + this.maxDate = false; + this.changed = false; + this.cleared = false; + this.ranges = {}; + this.opens = 'right'; + this.cb = function () { }; + this.format = '{MM}/{dd}/{yyyy}'; + this.separator = ' - '; + this.showWeekNumbers = false; + this.buttonClasses = ['btn-success']; + this.locale = { + applyLabel: 'Apply', + clearLabel:"Clear", + fromLabel: 'From', + toLabel: 'To', + weekLabel: 'W', + customRangeLabel: 'Custom Range', + daysOfWeek: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr','Sa'], + monthNames: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + firstDay: 0 + }; + + localeObject = this.locale; + + this.leftCalendar = { + month: Date.create('today').set({ day: 1, month: this.startDate.getMonth(), year: this.startDate.getFullYear() }), + calendar: Array() + }; + + this.rightCalendar = { + month: Date.create('today').set({ day: 1, month: this.endDate.getMonth(), year: this.endDate.getFullYear() }), + calendar: Array() + }; + + //element that triggered the date range picker + this.element = $(element); + + if (this.element.hasClass('pull-right')) + this.opens = 'left'; + + if (this.element.is('input')) { + this.element.on({ + click: $.proxy(this.show, this), + focus: $.proxy(this.show, this) + }); + } else { + this.element.on('click', $.proxy(this.show, this)); + } + + if (hasOptions) { + if(typeof options.locale == 'object') { + $.each(localeObject, function (property, value) { + localeObject[property] = options.locale[property] || value; + }); + } + } + + var DRPTemplate = ''; + + this.container = $(DRPTemplate).appendTo('body'); + + if (hasOptions) { + + if (typeof options.format == 'string') + this.format = options.format; + + if (typeof options.separator == 'string') + this.separator = options.separator; + + if (typeof options.startDate == 'string') + this.startDate = Date.create(options.startDate); + + if (typeof options.endDate == 'string') + this.endDate = Date.create(options.endDate); + + if (typeof options.minDate == 'string') + this.minDate = Date.create(options.minDate); + + if (typeof options.maxDate == 'string') + this.maxDate = Date.create(options.maxDate); + + + if (typeof options.startDate == 'object') + this.startDate = options.startDate; + + if (typeof options.endDate == 'object') + this.endDate = options.endDate; + + if (typeof options.minDate == 'object') + this.minDate = options.minDate; + + if (typeof options.maxDate == 'object') + this.maxDate = options.maxDate; + + if (typeof options.ranges == 'object') { + for (var range in options.ranges) { + + var start = options.ranges[range][0]; + var end = options.ranges[range][1]; + + if (typeof start == 'string') + start = Date.create(start); + + if (typeof end == 'string') + end = Date.create(end); + + // If we have a min/max date set, bound this range + // to it, but only if it would otherwise fall + // outside of the min/max. + if (this.minDate && start < this.minDate) + start = this.minDate; + + if (this.maxDate && end > this.maxDate) + end = this.maxDate; + + // If the end of the range is before the minimum (if min is set) OR + // the start of the range is after the max (also if set) don't display this + // range option. + if ((this.minDate && end < this.minDate) || (this.maxDate && start > this.maxDate)) + { + continue; + } + + this.ranges[range] = [start, end]; + } + + var list = '
    '; + for (var range in this.ranges) { + list += '
  • ' + range + '
  • '; + } + list += '
  • ' + this.locale.customRangeLabel + '
  • '; + list += '
'; + this.container.find('.ranges').prepend(list); + } + + // update day names order to firstDay + if (typeof options.locale == 'object') { + if (typeof options.locale.firstDay == 'number') { + this.locale.firstDay = options.locale.firstDay; + var iterator = options.locale.firstDay; + while (iterator > 0) { + this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift()); + iterator--; + } + } + } + + if (typeof options.opens == 'string') + this.opens = options.opens; + + if (typeof options.showWeekNumbers == 'boolean') { + this.showWeekNumbers = options.showWeekNumbers; + } + + if (typeof options.buttonClasses == 'string') { + this.buttonClasses = [options.buttonClasses]; + } + + if (typeof options.buttonClasses == 'object') { + this.buttonClasses = options.buttonClasses; + } + + } + + //apply CSS classes to buttons + var c = this.container; + $.each(this.buttonClasses, function (idx, val) { + c.find('button').addClass(val); + }); + + if (this.opens == 'right') { + //swap calendar positions + var left = this.container.find('.calendar.left'); + var right = this.container.find('.calendar.right'); + left.removeClass('left').addClass('right'); + right.removeClass('right').addClass('left'); + } + + if (typeof options == 'undefined' || typeof options.ranges == 'undefined') + this.container.find('.calendar').show(); + + if (typeof cb == 'function') + this.cb = cb; + + this.container.addClass('opens' + this.opens); + + //event listeners + this.container.on('mousedown', $.proxy(this.mousedown, this)); + this.container.find('.calendar').on('click', '.prev', $.proxy(this.clickPrev, this)); + this.container.find('.calendar').on('click', '.next', $.proxy(this.clickNext, this)); + this.container.find('.ranges').on('click', 'button.applyBtn', $.proxy(this.clickApply, this)); + this.container.find('.ranges').on('click', 'button.clearBtn', $.proxy(this.clickClear, this)); + + this.container.find('.calendar').on('click', 'td.available', $.proxy(this.clickDate, this)); + this.container.find('.calendar').on('mouseenter', 'td.available', $.proxy(this.enterDate, this)); + this.container.find('.calendar').on('mouseleave', 'td.available', $.proxy(this.updateView, this)); + + this.container.find('.ranges').on('click', 'li', $.proxy(this.clickRange, this)); + this.container.find('.ranges').on('mouseenter', 'li', $.proxy(this.enterRange, this)); + this.container.find('.ranges').on('mouseleave', 'li', $.proxy(this.updateView, this)); + + this.element.on('keyup', $.proxy(this.updateFromControl, this)); + + this.updateView(); + this.updateCalendars(); + + }; + + DateRangePicker.prototype = { + + constructor: DateRangePicker, + + mousedown: function (e) { + e.stopPropagation(); + e.preventDefault(); + }, + + updateView: function () { + this.leftCalendar.month.set({ month: this.startDate.getMonth(), year: this.startDate.getFullYear() }); + this.rightCalendar.month.set({ month: this.endDate.getMonth(), year: this.endDate.getFullYear() }); + + this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format)); + this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format)); + + if (this.startDate.is(this.endDate) || this.startDate.isBefore(this.endDate)) { + this.container.find('button.applyBtn').removeAttr('disabled'); + } else { + this.container.find('button.applyBtn').attr('disabled', 'disabled'); + } + }, + + updateFromControl: function () { + if (!this.element.is('input')) return; + + var dateString = this.element.val().split(this.separator); + var start = Date.create(dateString[0]); + var end = Date.create(dateString[1]); + + if (start == null || end == null) return; + if (end.isBefore(start)) return; + + this.startDate = start; + this.endDate = end; + + this.updateView(); + this.cb(this.startDate, this.endDate); + this.updateCalendars(); + }, + + notify: function () { + if (!this.cleared) { + this.updateView(); + } + + if (this.element.is('input')) { + this.element.val(this.cleared ? '' : this.startDate.format(this.format) + this.separator + this.endDate.format(this.format)); + } + var arg1 = (this.cleared ? null : this.startDate), + arg2 = (this.cleared ? null : this.endDate); + this.cleared = false; + this.cb(arg1,arg2); + }, + + move: function () { + if (this.opens == 'left') { + this.container.css({ + top: this.element.offset().top + this.element.outerHeight(), + right: $(window).width() - this.element.offset().left - this.element.outerWidth(), + left: 'auto' + }); + } else { + this.container.css({ + top: this.element.offset().top + this.element.outerHeight(), + left: this.element.offset().left, + right: 'auto' + }); + } + }, + + show: function (e) { + this.container.show(); + this.move(); + + if (e) { + e.stopPropagation(); + e.preventDefault(); + } + + this.changed = false; + + this.element.trigger('shown',{target:e.target,picker:this}); + + $(document).on('mousedown', $.proxy(this.hide, this)); + }, + + hide: function (e) { + this.container.hide(); + $(document).off('mousedown', this.hide); + + if (this.changed) { + this.changed = false; + this.notify(); + } + }, + + enterRange: function (e) { + var label = e.target.innerHTML; + if (label == this.locale.customRangeLabel) { + this.updateView(); + } else { + var dates = this.ranges[label]; + this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.format)); + this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.format)); + } + }, + + clickRange: function (e) { + var label = e.target.innerHTML; + if (label == this.locale.customRangeLabel) { + this.container.find('.calendar').show(); + } else { + var dates = this.ranges[label]; + + this.startDate = dates[0]; + this.endDate = dates[1]; + + this.leftCalendar.month.set({ month: this.startDate.getMonth(), year: this.startDate.getFullYear() }); + this.rightCalendar.month.set({ month: this.endDate.getMonth(), year: this.endDate.getFullYear() }); + this.updateCalendars(); + + this.changed = true; + + this.container.find('.calendar').hide(); + this.hide(); + } + }, + + clickPrev: function (e) { + var cal = $(e.target).parents('.calendar'); + if (cal.hasClass('left')) { + this.leftCalendar.month.addMonths(-1); + } else { + this.rightCalendar.month.addMonths(-1); + } + this.updateCalendars(); + }, + + clickNext: function (e) { + var cal = $(e.target).parents('.calendar'); + if (cal.hasClass('left')) { + this.leftCalendar.month.addMonths(1); + } else { + this.rightCalendar.month.addMonths(1); + } + this.updateCalendars(); + }, + + enterDate: function (e) { + + var title = $(e.target).attr('title'); + var row = title.substr(1, 1); + var col = title.substr(3, 1); + var cal = $(e.target).parents('.calendar'); + + if (cal.hasClass('left')) { + this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].format(this.format)); + } else { + this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].format(this.format)); + } + + }, + + clickDate: function (e) { + var title = $(e.target).attr('title'); + var row = title.substr(1, 1); + var col = title.substr(3, 1); + var cal = $(e.target).parents('.calendar'); + + if (cal.hasClass('left')) { + startDate = this.leftCalendar.calendar[row][col]; + endDate = this.endDate; + this.element.trigger('clicked',{ + dir: 'left', + picker: this + }); + } else { + startDate = this.startDate; + endDate = this.rightCalendar.calendar[row][col]; + this.element.trigger('clicked',{ + dir: 'right', + picker: this + }); + } + + cal.find('td').removeClass('active'); + + if (startDate.is(endDate) || startDate.isBefore(endDate)) { + $(e.target).addClass('active'); + if (!startDate.is(this.startDate) || !endDate.is(this.endDate)) + this.changed = true; + this.startDate = startDate; + this.endDate = endDate; + } + else if (startDate.isAfter(endDate)) { + $(e.target).addClass('active'); + this.changed = true; + this.startDate = startDate; + this.endDate = startDate.clone().addDays(1); + } + + this.leftCalendar.month.set({ month: this.startDate.getMonth(), year: this.startDate.getFullYear() }); + this.rightCalendar.month.set({ month: this.endDate.getMonth(), year: this.endDate.getFullYear() }); + this.updateCalendars(); + }, + + clickApply: function (e) { + this.hide(); + }, + + clickClear: function (e) { + this.changed = true; + this.cleared = true; + this.hide(); + }, + + updateCalendars: function () { + this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.getMonth(), this.leftCalendar.month.getFullYear()); + this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.getMonth(), this.rightCalendar.month.getFullYear()); + this.container.find('.calendar.left').html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate)); + this.container.find('.calendar.right').html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.startDate, this.maxDate)); + this.element.trigger('updated',this); + }, + + buildCalendar: function (month, year) { + + var firstDay = Date.create('today').set({ day: 1, month: month, year: year }); + var lastMonth = firstDay.clone().addDays(-1).getMonth(); + var lastYear = firstDay.clone().addDays(-1).getFullYear(); + + var daysInMonth = this.getDaysInMonth(year, month); + var daysInLastMonth = this.getDaysInMonth(lastYear, lastMonth); + + var dayOfWeek = firstDay.getDay(); + + //initialize a 6 rows x 7 columns array for the calendar + var calendar = Array(); + for (var i = 0; i < 6; i++) { + calendar[i] = Array(); + } + + //populate the calendar with date objects + var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1; + if (startDay > daysInLastMonth) + startDay -= 7; + + if (dayOfWeek == this.locale.firstDay) + startDay = daysInLastMonth - 6; + + var curDate = Date.create('today').set({ day: startDay, month: lastMonth, year: lastYear }); + for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = curDate.clone().addDays(1)) { + if (i > 0 && col % 7 == 0) { + col = 0; + row++; + } + calendar[row][col] = curDate; + } + + return calendar; + + }, + + renderCalendar: function (calendar, selected, minDate, maxDate) { + var html = ''; + html += ''; + html += ''; + + // add empty cell for week number + if (this.showWeekNumbers) + html += ''; + + if (!minDate || minDate < calendar[1][1]) + { + html += ''; + } + else + { + html += ''; + } + html += ''; + if (!maxDate || maxDate > calendar[1][1]) + { + html += ''; + } + else + { + html += ''; + } + + html += ''; + html += ''; + + // add week number label + if (this.showWeekNumbers) + html += ''; + + $.each(this.locale.daysOfWeek, function (index, dayOfWeek) { + html += ''; + }); + + html += ''; + html += ''; + html += ''; + + for (var row = 0; row < 6; row++) { + html += ''; + + // add week number + if (this.showWeekNumbers) + html += ''; + + for (var col = 0; col < 7; col++) { + var cname = 'available '; + cname += (calendar[row][col].getMonth() == calendar[1][1].getMonth()) ? '' : 'off'; + + // Normalise the time so the comparison won't fail + selected.setHours(0,0,0,0); + + if ( (minDate && calendar[row][col] < minDate) || (maxDate && calendar[row][col] > maxDate)) + { + cname = ' off disabled '; + } + else if (calendar[row][col].is(selected)) + { + cname += ' active '; + if (calendar[row][col].is(this.startDate)) { cname += ' start-date '; } + if (calendar[row][col].is(this.endDate)) { cname += ' end-date '; } + } + else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate) + { + cname += ' in-range '; + if (calendar[row][col].is(this.startDate)) { cname += ' start-date '; } + if (calendar[row][col].is(this.endDate)) { cname += ' end-date '; } + } + + var title = 'r' + row + 'c' + col; + html += ''; + } + html += ''; + } + + html += ''; + html += '
' + this.locale.monthNames[calendar[1][1].getMonth()] + calendar[1][1].format(' {yyyy}') + '
' + this.locale.weekLabel + '' + dayOfWeek + '
' + calendar[row][0].getWeek() + '' + calendar[row][col].getDate() + '
'; + + return html; + + }, + + getDaysInMonth: function (y, m) { + return /8|3|5|10/.test(--m)?30:m==1?(!(y%4)&&y%100)||!(y%400)?29:28:31; + } + + }; + + $.fn.daterangepicker = function (options, cb) { + this.each(function() { + var el = $(this); + if (!el.data('daterangepicker')) + el.data('daterangepicker', new DateRangePicker(el, options, cb)); + }); + return this; + }; + +} (window.jQuery); + --- /dev/null +++ b/js/script.js~ @@ -1,1 +1,136 @@ +$(function() { + // Set the default dates + var startDate = Date.create().addDays(-6), // 7 days ago + endDate = Date.create(); // today + + var range = $('#range'); + + // Show the dates in the range input + range.val(startDate.format('{MM}/{dd}/{yyyy}') + ' - ' + endDate.format('{MM}/{dd}/{yyyy}')); + + // Load chart + ajaxLoadChart(startDate,endDate); + + range.daterangepicker({ + + startDate: startDate, + endDate: endDate, + + ranges: { + 'Today': ['today', 'today'], + 'Yesterday': ['yesterday', 'yesterday'], + 'Last 7 Days': [Date.create().addDays(-6), 'today'], + 'Last 30 Days': [Date.create().addDays(-29), 'today'] + } + },function(start, end){ + + ajaxLoadChart(start, end); + + }); + + // The tooltip shown over the chart + var tt = $('
').appendTo('body'), + topOffset = -32; + + var data = { + "xScale" : "time", + "yScale" : "linear", + "main" : [{ + className : ".stats", + "data" : [] + }] + }; + + var opts = { + paddingLeft : 50, + paddingTop : 20, + paddingRight : 10, + axisPaddingLeft : 25, + tickHintX: 9, // How many ticks to show horizontally + + dataFormatX : function(x) { + + // This turns converts the timestamps coming from + // ajax.php into a proper JavaScript Date object + + return Date.create(x); + }, + + tickFormatX : function(x) { + + // Provide formatting for the x-axis tick labels. + // This uses sugar's format method of the date object. + + return x.format('{MM}/{dd}'); + }, + + "mouseover": function (d, i) { + var pos = $(this).offset(); + + tt.text(d.x.format('{Month} {ord}') + ': ' + d.y).css({ + + top: topOffset + pos.top, + left: pos.left + + }).show(); + }, + + "mouseout": function (x) { + tt.hide(); + } + }; + + // Create a new xChart instance, passing the type + // of chart a data set and the options object + + var chart = new xChart('line-dotted', data, '#chart' , opts); + + // Function for loading data via AJAX and showing it on the chart + function ajaxLoadChart(startDate,endDate) { + + // If no data is passed (the chart was cleared) + + if(!startDate || !endDate){ + chart.setData({ + "xScale" : "time", + "yScale" : "linear", + "main" : [{ + className : ".stats", + data : [] + }] + }); + + return; + } + + // Otherwise, issue an AJAX request + + $.getJSON('ajax.php', { + + start: startDate.format('{yyyy}-{MM}-{dd}'), + end: endDate.format('{yyyy}-{MM}-{dd}') + + }, function(data) { + + var set = []; + $.each(data, function() { + set.push({ + x : this.label, + y : parseInt(this.value, 10) + }); + }); + + chart.setData({ + "xScale" : "time", + "yScale" : "linear", + "main" : [{ + className : ".stats", + data : set + }] + }); + + }); + } +}); + --- /dev/null +++ b/js/sugar.min.js @@ -1,1 +1,120 @@ - +/* + * Sugar Library v1.3.7 + * + * Freely distributable and licensed under the MIT-style license. + * Copyright (c) 2012 Andrew Plummer + * http://sugarjs.com/ + * + * ---------------------------- */ +(function(){var k=true,l=null,n=false;function aa(a){return function(){return a}}var p=Object,q=Array,r=RegExp,s=Date,t=String,u=Number,v=Math,ba=typeof global!=="undefined"?global:this,ca=p.defineProperty&&p.defineProperties,x="Array,Boolean,Date,Function,Number,String,RegExp".split(","),da=y(x[0]),ea=y(x[1]),fa=y(x[2]),A=y(x[3]),B=y(x[4]),C=y(x[5]),D=y(x[6]);function y(a){return function(b){return p.prototype.toString.call(b)==="[object "+a+"]"}} +function ga(a){if(!a.SugarMethods){ha(a,"SugarMethods",{});E(a,n,n,{restore:function(){var b=arguments.length===0,c=F(arguments);G(a.SugarMethods,function(d,e){if(b||c.indexOf(d)>-1)ha(e.wa?a.prototype:a,d,e.method)})},extend:function(b,c,d){E(a,d!==n,c,b)}})}}function E(a,b,c,d){var e=b?a.prototype:a,f;ga(a);G(d,function(h,i){f=e[h];if(typeof c==="function")i=ia(e[h],i,c);if(c!==n||!e[h])ha(e,h,i);a.SugarMethods[h]={wa:b,method:i,Da:f}})} +function H(a,b,c,d,e){var f={};d=C(d)?d.split(","):d;d.forEach(function(h,i){e(f,h,i)});E(a,b,c,f)}function ia(a,b,c){return function(){return a&&(c===k||!c.apply(this,arguments))?a.apply(this,arguments):b.apply(this,arguments)}}function ha(a,b,c){if(ca)p.defineProperty(a,b,{value:c,configurable:k,enumerable:n,writable:k});else a[b]=c}function F(a,b){var c=[],d;for(d=0;d=b;){e.push(a);c&&c.call(this,a);a+=d||1}return e}function N(a,b,c){c=v[c||"round"];var d=v.pow(10,v.abs(b||0));if(b<0)d=1/d;return c(a*d)/d}function qa(a,b){return N(a,b,"floor")}function O(a,b,c,d){d=v.abs(a).toString(d||10);d=ra(b-d.replace(/\.\d+/,"").length,"0")+d;if(c||a<0)d=(a<0?"-":"+")+d;return d} +function sa(a){if(a>=11&&a<=13)return"th";else switch(a%10){case 1:return"st";case 2:return"nd";case 3:return"rd";default:return"th"}}function ta(){return"\t\n\u000b\u000c\r \u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u2028\u2029\u3000\ufeff"}function ra(a,b){return q(v.max(0,I(a)?a:1)+1).join(b||"")}function ua(a,b){var c=a.toString().match(/[^/]*$/)[0];if(b)c=(c+b).split("").sort().join("").replace(/([gimy])\1+/g,"$1");return c} +function P(a){C(a)||(a=t(a));return a.replace(/([\\/'*+?|()\[\]{}.^$])/g,"\\$1")}function va(a,b){var c=typeof a,d,e,f,h,i,j;if(c==="string")return a;f=p.prototype.toString.call(a);d=ma(a);e=f==="[object Array]";if(a!=l&&d||e){b||(b=[]);if(b.length>1)for(j=b.length;j--;)if(b[j]===a)return"CYC";b.push(a);d=t(a.constructor);h=e?a:p.keys(a).sort();for(j=0;j