<commit_before>//! moment.js locale configuration
//! locale : Marathi (mr)
//! author : Harshad Kale : https://github.com/kalehv
//! author : Vivek Athalye : https://github.com/vnathalye

(function (global, factory) {
   typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('../moment')) :
   typeof define === 'function' && define.amd ? define(['moment'], factory) :
   factory(global.moment)
}(this, function (moment) { 'use strict';

    var symbolMap = {
        '1': '१',
        '2': '२',
        '3': '३',
        '4': '४',
        '5': '५',
        '6': '६',
        '7': '७',
        '8': '८',
        '9': '९',
        '0': '०'
    },
    numberMap = {
        '१': '1',
        '२': '2',
        '३': '3',
        '४': '4',
        '५': '5',
        '६': '6',
        '७': '7',
        '८': '8',
        '९': '9',
        '०': '0'
    };

    function mr_relativeTime(number, withoutSuffix, string, isFuture)
    {
        var output = "";
        if (withoutSuffix) {
            switch(string) {
                case "s": output = 'काही सेकंद'; break;
                case "m": output = 'एक मिनिट'; break;
                case "mm": output = '%d मिनिटे'; break;
                case "h": output = 'एक तास'; break;
                case "hh": output = '%d तास'; break;
                case "d": output = 'एक दिवस'; break;
                case "dd": output = '%d दिवस'; break;
                case "M": output = 'एक महिना'; break;
                case "MM": output = '%d महिने'; break;
                case "y": output = 'एक वर्ष'; break;
                case "yy": output = '%d वर्षे'; break;
            }
        }
        else {
            switch (string) {
                case "s": output = 'काही सेकंदां'; break;
                case "m": output = 'एका मिनिटा'; break;
                case "mm": output = '%d मिनिटां'; break;
                case "h": output = 'एका तासा'; break;
                case "hh": output = '%d तासां'; break;
                case "d": output = 'एका दिवसा'; break;
                case "dd": output = '%d दिवसां'; break;
                case "M": output = 'एका महिन्या'; break;
                case "MM": output = '%d महिन्यां'; break;
                case "y": output = 'एका वर्षा'; break;
                case "yy": output = '%d वर्षां'; break;
            }
        }
        return output.replace(/%d/i, number);
    }

    var mr = moment.defineLocale('mr', {
        months : 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split('_'),
        monthsShort: 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split('_'),
        weekdays : 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
        weekdaysShort : 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'),
        weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
        longDateFormat : {
            LT : 'A h:mm वाजता',
            LTS : 'A h:mm:ss वाजता',
            L : 'DD/MM/YYYY',
            LL : 'D MMMM YYYY',
            LLL : 'D MMMM YYYY, A h:mm वाजता',
            LLLL : 'dddd, D MMMM YYYY, A h:mm वाजता'
        },
        calendar : {
            sameDay : '[आज] LT',
            nextDay : '[उद्या] LT',
            nextWeek : 'dddd, LT',
            lastDay : '[काल] LT',
            lastWeek: '[मागील] dddd, LT',
            sameElse : 'L'
        },
        relativeTime: {
            future: '%sमध्ये',
            past: '%sपूर्वी',
            s: mr_relativeTime,
            m: mr_relativeTime,
            mm: mr_relativeTime,
            h: mr_relativeTime,
            hh: mr_relativeTime,
            d: mr_relativeTime,
            dd: mr_relativeTime,
            M: mr_relativeTime,
            MM: mr_relativeTime,
            y: mr_relativeTime,
            yy: mr_relativeTime
        },
        preparse: function (string) {
            return string.replace(/[१२३४५६७८९०]/g, function (match) {
                return numberMap[match];
            });
        },
        postformat: function (string) {
            return string.replace(/\d/g, function (match) {
                return symbolMap[match];
            });
        },
        meridiemParse: /रात्री|सकाळी|दुपारी|सायंकाळी/,
        meridiemHour : function (hour, meridiem) {
            if (hour === 12) {
                hour = 0;
            }
            if (meridiem === 'रात्री') {
                return hour < 4 ? hour : hour + 12;
            } else if (meridiem === 'सकाळी') {
                return hour;
            } else if (meridiem === 'दुपारी') {
                return hour >= 10 ? hour : hour + 12;
            } else if (meridiem === 'सायंकाळी') {
                return hour + 12;
            }
        },
        meridiem: function (hour, minute, isLower) {
            if (hour < 4) {
                return 'रात्री';
            } else if (hour < 10) {
                return 'सकाळी';
            } else if (hour < 17) {
                return 'दुपारी';
            } else if (hour < 20) {
                return 'सायंकाळी';
            } else {
                return 'रात्री';
            }
        },
        week : {
            dow : 0, // Sunday is the first day of the week.
            doy : 6  // The week that contains Jan 1st is the first week of the year.
        }
    });

    return mr;

}));<commit_msg>Revert "Changed relativeTime"<commit_after>//! moment.js locale configuration
//! locale : Marathi (mr)
//! author : Harshad Kale : https://github.com/kalehv

(function (global, factory) {
   typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('../moment')) :
   typeof define === 'function' && define.amd ? define(['moment'], factory) :
   factory(global.moment)
}(this, function (moment) { 'use strict';

    var symbolMap = {
        '1': '१',
        '2': '२',
        '3': '३',
        '4': '४',
        '5': '५',
        '6': '६',
        '7': '७',
        '8': '८',
        '9': '९',
        '0': '०'
    },
    numberMap = {
        '१': '1',
        '२': '2',
        '३': '3',
        '४': '4',
        '५': '5',
        '६': '6',
        '७': '7',
        '८': '8',
        '९': '9',
        '०': '0'
    };

    var mr = moment.defineLocale('mr', {
        months : 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split('_'),
        monthsShort: 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split('_'),
        weekdays : 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'),
        weekdaysShort : 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'),
        weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
        longDateFormat : {
            LT : 'A h:mm वाजता',
            LTS : 'A h:mm:ss वाजता',
            L : 'DD/MM/YYYY',
            LL : 'D MMMM YYYY',
            LLL : 'D MMMM YYYY, A h:mm वाजता',
            LLLL : 'dddd, D MMMM YYYY, A h:mm वाजता'
        },
        calendar : {
            sameDay : '[आज] LT',
            nextDay : '[उद्या] LT',
            nextWeek : 'dddd, LT',
            lastDay : '[काल] LT',
            lastWeek: '[मागील] dddd, LT',
            sameElse : 'L'
        },
        relativeTime : {
            future : '%s नंतर',
            past : '%s पूर्वी',
            s : 'सेकंद',
            m: 'एक मिनिट',
            mm: '%d मिनिटे',
            h : 'एक तास',
            hh : '%d तास',
            d : 'एक दिवस',
            dd : '%d दिवस',
            M : 'एक महिना',
            MM : '%d महिने',
            y : 'एक वर्ष',
            yy : '%d वर्षे'
        },
        preparse: function (string) {
            return string.replace(/[१२३४५६७८९०]/g, function (match) {
                return numberMap[match];
            });
        },
        postformat: function (string) {
            return string.replace(/\d/g, function (match) {
                return symbolMap[match];
            });
        },
        meridiemParse: /रात्री|सकाळी|दुपारी|सायंकाळी/,
        meridiemHour : function (hour, meridiem) {
            if (hour === 12) {
                hour = 0;
            }
            if (meridiem === 'रात्री') {
                return hour < 4 ? hour : hour + 12;
            } else if (meridiem === 'सकाळी') {
                return hour;
            } else if (meridiem === 'दुपारी') {
                return hour >= 10 ? hour : hour + 12;
            } else if (meridiem === 'सायंकाळी') {
                return hour + 12;
            }
        },
        meridiem: function (hour, minute, isLower) {
            if (hour < 4) {
                return 'रात्री';
            } else if (hour < 10) {
                return 'सकाळी';
            } else if (hour < 17) {
                return 'दुपारी';
            } else if (hour < 20) {
                return 'सायंकाळी';
            } else {
                return 'रात्री';
            }
        },
        week : {
            dow : 0, // Sunday is the first day of the week.
            doy : 6  // The week that contains Jan 1st is the first week of the year.
        }
    });

    return mr;

}));<|endoftext|>


<commit_before>locale.nl = {
    modes: {
        add_area: {
            title: "Vlakken",
            description: "Voeg parken, gebouwen, meren of andere vlakken aan de kaart toe.",
            tail: "Klik in de kaart om het tekenen van een vlak zoals een park, gebouw of meer te starten."
        },
        add_line: {
            title: "Lijn",
            description: "Lijnen zijn rijkswegen, straten, voetpaden of kanalen.",
            tail: "Klik in de kaart om het tekenen van straat, pad of route te starten."
        },
        add_point: {
            title: "Punt",
            description: "Restaurants, monumenten en brievenbussen zijn punten.",
            tail: "Klik in de kaart om een punt toe te voegen."
        },
        browse: {
            title: "Navigatie",
            description: "Verschuiven en vergroten/verkleinen van de kaartuitsnede."
        },
        draw_area: {
            tail: "Klik om punten aan het vlak toe te voegen. Klik op het eerste punt om het vlak te sluiten."
        },
        draw_line: {
            tail: "Klik om  meer punten aan de lijn toe te voegen. Klik op een andere lijn om de lijnen te verbinden en dubbelklik om het tekenen te stoppen."
        }
    },

    operations: {
        add: {
            annotation: {
                point: "Punt toegevoegd.",
                vertex: "Stützpunkt einem Weg hinzugefügt."
            }
        },
        start: {
            annotation: {
                line: "Lijn begonnen.",
                area: "Vlak begonnen."
            }
        },
        'continue': {
            annotation: {
                line: "Lijn voortgezet.",
                area: "Vlak voortgezet."
            }
        },
        cancel_draw: {
            annotation: "Tekenen afgebroken."
        },
        change_tags: {
            annotation: "Tags veranderd."
        },
        circularize: {
            title: "Abrunden",
            description: "Runde dies ab.",
            key: "O",
            annotation: {
                line: "Runde eine Linie ab.",
                area: "Runde eine Fläche ab."
            }
        },
        orthogonalize: {
            title: "Rechtwinkligkeit herstellen",
            description: "Diese Ecken rechtwinklig ausrichten.",
            key: "Q",
            annotation: {
                line: "Die Ecken einer Linie rechtwinklig ausgerichtet.",
                area: "Die Ecken einer Fläche rechtwinklig ausgerichtet."
            }
        },
        'delete': {
            title: "Verwijderen",
            description: "Verwijder deze van de kaart.",
            key: "⌫",
            annotation: {
                point: "Punt verwijderd.",
                vertex: "Stützpunkt aus einem Weg gelöscht.",
                line: "Lijn verwijderd.",
                area: "Vlak verwijderd.",
                relation: "Relatie verwijderd.",
                multiple: "{n} objecten verwijderd."
            }
        },
        connect: {
            annotation: {
                point: "Weg mit einem Punkt verbunden.",
                vertex: "Weg mit einem anderem Weg verbunden.",
                line: "Weg mit einer Linie verbunden.",
                area: "Weg mit einer Fläche verbunden."
            }
        },
        disconnect: {
            title: "Trennen",
            description: "Trenne diese Wege voneinander.",
            key: "D",
            annotation: "Wege getrennt."
        },
        merge: {
            title: "Vereinigen",
            description: "Vereinige diese Linien.",
            key: "C",
            annotation: "{n} Linien vereinigt."
        },
        move: {
            title: "Verschuiven",
            description: "Verschuif dit object naar een andere plek.",
            key: "M",
            annotation: {
                point: "Punt verschoven.",
                vertex: "Stützpunkt in einen Weg veschoben.",
                line: "Lijn verschoven.",
                area: "Vlak verschoven."
            }
        },
        reverse: {
            title: "Omdraaien",
            description: "Draai de richting van deze lijn om.",
            key: "V",
            annotation: "Lijnrichting omgedraaid."
        },
        split: {
            title: "Splitsen",
            description: "Splits dit in twee wegen op dit punt.",
            key: "X",
            annotation: "Weg opgesplitst."
        }
    },

    nothing_to_undo: "Nichts zum Rückgängigmachen.",
    nothing_to_redo: "Nichts zum Wiederherstellen.",

    just_edited: "Je hebt zojuist OpenStreetMap aangepast!",
    browser_notice: "Deze editor wordt door Firefox, Chrome, Safari, Opera en Internet Explorer (versie 9 en hoger) ondersteund. Download een nieuwere versie van je browser of gebruik Potlatch 2 om de kaart aan te passen.",
    view_on_osm: "Op OSM bekijken",
    zoom_in_edit: "Zoom in om de kaart aan te passen.",
    logout: "Afmelden",
    report_a_bug: "Softwareprobleem melden",

    commit: {
        title: "Aanpassingen opslaan",
        description_placeholder: "Een korte omschrijving van je bijdragen",
        upload_explanation: "Aanpassingen die je als {user} uploadt worden zichtbaar op alle kaarten die OpenStreetMap gebruiken.",
        save: "Opslaan",
        cancel: "Afbreken",
        warnings: "Waarschuwingen",
        modified: "Aangepast",
        deleted: "Verwijderd",
        created: "Aangemaakt"
    },

    contributors: {
        list: "Deze kaartuitsnede bevat bijdragen van:",
        truncated_list: "Deze kaartuitsnede bevat bijdragen van: {users} en {count} anderen"
    },

    geocoder: {
        title: "Zoek een plaats",
        placeholder: "Zoek een plaats",
        no_results: "De plaats '{name}' kan niet worden gevonden"
    },

    geolocate: {
        title: "Toen mijn locatie"
    },

    inspector: {
        no_documentation_combination: "Voor dit attribuut is geen documentatie beschikbaar.",
        no_documentation_key: "Voor dit trefwoord is geen documentatie beschikbaar",
        new_tag: "Nieuw attribuut",
        edit_tags: "Attribuut aanpassen",
        okay: "OK",
        view_on_osm: "op OSM bekijken"
    },

    layerswitcher: {
        title: "Achtergrond",
        description: "Achtergrondinstellingen",
        percent_brightness: "{opacity}% helderheid",
        fix_misalignment: "Fehlerhafte Ausrichtung reparieren",
        reset: "Terugzetten"
    },

    restore: {
        description: "Er zijn niet-opgeslagen aanpassingen uit een vorige sessie. Wil je deze aanpassingen herstellen?",
        restore: "Herstellen",
        reset: "Terugzetten"
    },

    save: {
        title: "Opslaan",
        help: "Sla de aanpassingen op op OpenStreetMap om deze voor andere gebruikers zichtbaar te maken",
        error: "Bij het opslaan is een fout opgetreden",
        uploading: "De aanpassingen zijn naar OpenStreetMap geüpload.",
        unsaved_changes: "Niet-opgeslagen aanpassingen beschikbaar",
    },

    splash: {
        welcome: "Welkom bij de iD OpenStreetMap editor",
        text: " Dit is een ontwikkelversie {version}. Voor meer informatie bezoek {website} of meld problemen op {github}."
    },

    source_switch: {
        live: "live",
        dev: "dev"
    },

    tag_reference: {
        description: "Beschreibung",
        on_wiki: "{tag} auf wiki.osm.org",
        used_with: "benutzt mit {type}"
    },

    validations: {
        untagged_point: "Punkt ohne Attribute, der kein Teil einer Linie oder Fläche ist",
        untagged_line: "Linie ohne Attribute",
        untagged_area: "Fläche ohne Attribute",
        tag_suggests_area: "Das Attribut {tag} suggeriert eine Fläche, ist aber keine Fläche",
        deprecated_tags: "Veralterte Attribute: {tags}"
    },

    zoom: {
        in: "Hineinzoomen",
        out: "Herauszoomen"
    }
};
<commit_msg>Finished translating all strings to Dutch<commit_after>locale.nl = {
    modes: {
        add_area: {
            title: "Vlak",
            description: "Voeg parken, gebouwen, meren of andere vlakken aan de kaart toe.",
            tail: "Klik in de kaart om het tekenen van een vlak zoals een park, gebouw of meer te starten."
        },
        add_line: {
            title: "Lijn",
            description: "Lijnen zijn bijvoorbeeld rijkswegen, straten, voetpaden of kanalen.",
            tail: "Klik in de kaart om het tekenen van straat, pad of route te starten."
        },
        add_point: {
            title: "Punt",
            description: "Restaurants, monumenten en brievenbussen zijn bijvoorbeeld punten.",
            tail: "Klik in de kaart om een punt toe te voegen."
        },
        browse: {
            title: "Navigatie",
            description: "Verschuif en zoom in op de kaart."
        },
        draw_area: {
            tail: "Klik om punten aan het vlak toe te voegen. Klik op het eerste punt om het vlak te sluiten."
        },
        draw_line: {
            tail: "Klik om meer punten aan de lijn toe te voegen. Klik op een andere lijn om de lijnen te verbinden en dubbelklik om de lijn af te sluiten."
        }
    },

    operations: {
        add: {
            annotation: {
                point: "Punt toegevoegd.",
                vertex: "Knoop aan een weg toegevoegd."
            }
        },
        start: {
            annotation: {
                line: "Lijn begonnen.",
                area: "Vlak begonnen."
            }
        },
        'continue': {
            annotation: {
                line: "Lijn voortgezet.",
                area: "Vlak voortgezet."
            }
        },
        cancel_draw: {
            annotation: "Tekenen afgebroken."
        },
        change_tags: {
            annotation: "Tags aangepast."
        },
        circularize: {
            title: "Rond maken",
            description: "Maak dit rond.",
            key: "O",
            annotation: {
                line: "Maak een lijn rond.",
                area: "Maak een vlak rond."
            }
        },
        orthogonalize: {
            title: "Haaks maken",
            description: "Maak deze hoeken haaks.",
            key: "Q",
            annotation: {
                line: "Hoeken van een lijn zijn haaks gemaakt.",
                area: "Hoeken van een vlak zijn haaks gemaakt."
            }
        },
        'delete': {
            title: "Verwijderen",
            description: "Verwijder dit van de kaart.",
            key: "⌫",
            annotation: {
                point: "Punt verwijderd.",
                vertex: "Knoop uit een weg verwijderd.",
                line: "Lijn verwijderd.",
                area: "Vlak verwijderd.",
                relation: "Relatie verwijderd.",
                multiple: "{n} objecten verwijderd."
            }
        },
        connect: {
            annotation: {
                point: "Weg aan een punt verbonden.",
                vertex: "Weg aan een andere weg verbonden.",
                line: "Weg aan een lijn  verbonden.",
                area: "Weg aan een vlak verbonden."
            }
        },
        disconnect: {
            title: "Losmaken",
            description: "Maak deze wegen van elkaar los.",
            key: "D",
            annotation: "Wegen losgemaakt."
        },
        merge: {
            title: "Samenvoegen",
            description: "Voeg deze lijnen samen.",
            key: "C",
            annotation: "{n} lijnen samengevoegd."
        },
        move: {
            title: "Verschuiven",
            description: "Verschuif dit object naar een andere plek.",
            key: "M",
            annotation: {
                point: "Punt verschoven.",
                vertex: "Knoop van een weg verschoven.",
                line: "Lijn verschoven.",
                area: "Vlak verschoven."
            }
        },
        reverse: {
            title: "Omdraaien",
            description: "Draai de richting van deze lijn om.",
            key: "V",
            annotation: "Lijnrichting omgedraaid."
        },
        split: {
            title: "Splitsen",
            description: "Splits deze weg op het geselecteerde punt.",
            key: "X",
            annotation: "Weg opgesplitst."
        }
    },

    nothing_to_undo: "Niets om ongedaan te maken.",
    nothing_to_redo: "Niets om opnieuw uit te voeren.",

    just_edited: "Je hebt zojuist OpenStreetMap aangepast!",
    browser_notice: "Deze editor wordt door Firefox, Chrome, Safari, Opera en Internet Explorer (versie 9 en hoger) ondersteund. Download een nieuwere versie van je browser of gebruik Potlatch 2 om de kaart aan te passen.",
    view_on_osm: "Bekijk op OSM",
    zoom_in_edit: "Zoom in om de kaart aan te passen.",
    logout: "Afmelden",
    report_a_bug: "Meld een softwareprobleem",

    commit: {
        title: "Aanpassingen opslaan",
        description_placeholder: "Een korte omschrijving van je bijdragen",
        upload_explanation: "Aanpassingen die je als {user} uploadt worden zichtbaar op alle kaarten die de gegevens van OpenStreetMap gebruiken.",
        save: "Opslaan",
        cancel: "Afbreken",
        warnings: "Waarschuwingen",
        modified: "Aangepast",
        deleted: "Verwijderd",
        created: "Aangemaakt"
    },

    contributors: {
        list: "Deze kaartuitsnede bevat bijdragen van:",
        truncated_list: "Deze kaartuitsnede bevat bijdragen van: {users} en {count} anderen"
    },

    geocoder: {
        title: "Zoek een plaats",
        placeholder: "Zoek een plaats",
        no_results: "De plaats '{name}' kan niet worden gevonden"
    },

    geolocate: {
        title: "Toon mijn locatie"
    },

    inspector: {
        no_documentation_combination: "Voor deze tag is geen documentatie beschikbaar.",
        no_documentation_key: "Voor deze sleutel is geen documentatie beschikbaar",
        new_tag: "Nieuwe tag",
        edit_tags: "Tags aanpassen",
        okay: "OK",
        view_on_osm: "Bekijk op OSM"
    },

    layerswitcher: {
        title: "Achtergrond",
        description: "Achtergrondinstellingen",
        percent_brightness: "{opacity}% helderheid",
        fix_misalignment: "Repareer de verkeerde ligging",
        reset: "Ongedaan maken"
    },

    restore: {
        description: "Er zijn niet-opgeslagen aanpassingen uit een vorige sessie. Wil je deze aanpassingen behouden?",
        restore: "Behouden",
        reset: "Ongedaan maken"
    },

    save: {
        title: "Opslaan",
        help: "Sla de aanpassingen bij OpenStreetMap op om deze voor andere gebruikers zichtbaar te maken",
        error: "Bij het opslaan is een fout opgetreden",
        uploading: "De aanpassingen worden naar OpenStreetMap geüpload.",
        unsaved_changes: "Je hebt niet-opgeslagen aanpassingen",
    },

    splash: {
        welcome: "Welkom bij de iD OpenStreetMap editor",
        text: " Dit is een ontwikkelversie {version}. Voor meer informatie bezoek {website} of meld problemen op {github}."
    },

    source_switch: {
        live: "live",
        dev: "dev"
    },

    tag_reference: {
        description: "Omschrijving",
        on_wiki: "{tag} op wiki.osm.org",
        used_with: "gebruikt met {type}"
    },

    validations: {
        untagged_point: "Punt zonder tags, dat geen onderdeel is van een lijn of vlak",
        untagged_line: "Lijn zonder tags",
        untagged_area: "Vlak zonder tags",
        tag_suggests_area: "De tag {tag} suggereert dat de lijn een vlak is, maar het is geen vlak",
        deprecated_tags: "Afgeschafte tags: {tags}"
    },

    zoom: {
        in: "Inzoomen",
        out: "Uitzoomen"
    }
};
<|endoftext|>


<commit_before>define(module, function(exports, require) {

  var util = require('util');
  var qp = require('qp-utility');
  var fss = require('qp-library/fss');
  var os = require('os');

  var debug = /--inspect/.test(process.execArgv.join(' '));

  var log = function log() {
    console.log.apply(console, arguments);
  };

  log.clear = function() {
    if (debug) {
      console.clear();
    } else {
      if (process.platform === 'win32') {
        process.stdout.write('\033c');
      } else {
        process.stdout.write('\u001B[2J\u001B[0;0f');
      }
    }
  };

  log.dir = function(o, options) {
    console.log(util.inspect(o, options || { showHidden: false, depth: null, colors: true }));
  };

  log.file = function(log_file, o, eol_count) {
    fss.append(log_file, JSON.stringify(o, null, '  ') + qp.repeat(os.EOL, eol_count || 0));
  };

  log.error = function() {
    if (qp.is(arguments[0], 'error')) {
      console.error(util.inspect(arguments[0], arguments[1] || { showHidden: false, depth: null, colors: true }));
    } else {
      console.error(arguments[0], util.inspect(arguments[1], arguments[2] || { showHidden: false, depth: null, colors: true }));
    }
  };

  log.socket = function(type) {
    console.log.apply(console, qp.union([log.yellow('WS  ' + qp.rpad(type, 4))], qp.rest(arguments)));
  };

  log.postgres = function(type) {
    console.log.apply(console, qp.union([log.yellow('PG  ' + qp.rpad(type, 4))], qp.rest(arguments)));
  };

  if (debug) {
    var plain_text = function() { return qp.join(arguments, ' '); };
    log.blue_white = plain_text;
    log.red_white = plain_text;
    log.white_red = plain_text;
    log.yellow_black = plain_text;
    log.red = plain_text;
    log.green = plain_text;
    log.yellow = plain_text;
    log.blue = plain_text;
    log.magenta = plain_text;
    log.cyan = plain_text;
    log.white = plain_text;
  } else {
    log.blue_white = function() { return '\x1b[47m\x1b[34m' + qp.join(arguments, ' ') + '\x1b[0m\x1b[0m'; };
    log.red_white = function() { return '\x1b[47m\x1b[31m' + qp.join(arguments, ' ') + '\x1b[0m\x1b[0m'; };
    log.white_red = function() { return '\x1b[41m\x1b[37m' + qp.join(arguments, ' ') + '\x1b[0m\x1b[0m'; };
    log.yellow_black = function() { return '\x1b[43m\x1b[30m' + qp.join(arguments, ' ') + '\x1b[0m\x1b[0m'; };
    log.red = function() { return '\x1b[31m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.green = function() { return '\x1b[32m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.yellow = function() { return '\x1b[33m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.blue = function() { return '\x1b[34m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.magenta = function() { return '\x1b[35m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.cyan = function() { return '\x1b[36m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.white = function() { return '\x1b[37m' + qp.join(arguments, ' ') + '\x1b[0m'; };
  }

  exports('qp-library/log', log);

});
<commit_msg>prevent formatting chars in log file output<commit_after>define(module, function(exports, require) {

  var util = require('util');
  var qp = require('qp-utility');
  var fss = require('qp-library/fss');
  var os = require('os');
  var mode = {};

  var inspect = /--inspect/.test(process.execArgv.join(' '));
  mode[qp.lower(inspect ? 'INSPECT' : (process.env.log || 'STANDARD'))] = true;

  var log = function log() {
    console.log.apply(console, arguments);
  };

  log.clear = function() {
    if (mode.inspect) {
      console.clear();
    } else if (mode.deployed) {
      //
    } else {
      if (process.platform === 'win32') {
        process.stdout.write('\033c');
      } else {
        process.stdout.write('\u001B[2J\u001B[0;0f');
      }
    }
  };

  log.dir = function(o, options) {
    console.log(util.inspect(o, options || { showHidden: false, depth: null, colors: true }));
  };

  log.file = function(log_file, o, eol_count) {
    fss.append(log_file, JSON.stringify(o, null, '  ') + qp.repeat(os.EOL, eol_count || 0));
  };

  log.error = function() {
    if (qp.is(arguments[0], 'error')) {
      console.error(util.inspect(arguments[0], arguments[1] || { showHidden: false, depth: null, colors: true }));
    } else {
      console.error(arguments[0], util.inspect(arguments[1], arguments[2] || { showHidden: false, depth: null, colors: true }));
    }
  };

  log.socket = function(type) {
    console.log.apply(console, qp.union([log.yellow('WS  ' + qp.rpad(type, 4))], qp.rest(arguments)));
  };

  log.postgres = function(type) {
    console.log.apply(console, qp.union([log.yellow('PG  ' + qp.rpad(type, 4))], qp.rest(arguments)));
  };

  if (mode.inspect || mode.deployed) {
    var plain_text = function() { return qp.join(arguments, ' '); };
    log.blue_white = plain_text;
    log.red_white = plain_text;
    log.white_red = plain_text;
    log.yellow_black = plain_text;
    log.red = plain_text;
    log.green = plain_text;
    log.yellow = plain_text;
    log.blue = plain_text;
    log.magenta = plain_text;
    log.cyan = plain_text;
    log.white = plain_text;
  } else {
    log.blue_white = function() { return '\x1b[47m\x1b[34m' + qp.join(arguments, ' ') + '\x1b[0m\x1b[0m'; };
    log.red_white = function() { return '\x1b[47m\x1b[31m' + qp.join(arguments, ' ') + '\x1b[0m\x1b[0m'; };
    log.white_red = function() { return '\x1b[41m\x1b[37m' + qp.join(arguments, ' ') + '\x1b[0m\x1b[0m'; };
    log.yellow_black = function() { return '\x1b[43m\x1b[30m' + qp.join(arguments, ' ') + '\x1b[0m\x1b[0m'; };
    log.red = function() { return '\x1b[31m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.green = function() { return '\x1b[32m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.yellow = function() { return '\x1b[33m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.blue = function() { return '\x1b[34m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.magenta = function() { return '\x1b[35m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.cyan = function() { return '\x1b[36m' + qp.join(arguments, ' ') + '\x1b[0m'; };
    log.white = function() { return '\x1b[37m' + qp.join(arguments, ' ') + '\x1b[0m'; };
  }

  exports('qp-library/log', log);

});
<|endoftext|>


<commit_before>var dgram  = require('dgram')
  , sys    = require('sys')
  , net    = require('net')
  , msgpack = require('msgpack')
  , config = require('./config')
  , redis  = require('redis')

/* enums for message types and message levels */

var types = Object.freeze({
  LOG: 1,
  COUNTER: 2,
  TIMER: 3,
  DELETE_LOG: 4,
});

var levels = Object.freeze({
  DEBUG: 10,
  INFO: 20,
  WARNING: 30,
  ERROR: 40,
  FATAL: 50
});

var messagesReceived = 0;
var messagesReceivedPrev = 0;
var logMessages = {};
var counters = {};
var timers = {};
var debugInt, flushInt, logInt, trimInt, statsInt, server;

function redisErrback(err, ret) {
  if (err) {
    sys.log("redis error: " + err);
  }
}

/* Connect to redis, using the configuration options provided, falling
 * back on sane defaults.  Sets a few message handlers to deal with errors
 * and report the status of the connection.
 */

function redisConnect(config) {
  var port = Number(config.redis.port || 6379),
      host = config.redis.host || "localhost",
      options = config.redisOptions || {};

  var client = redis.createClient(port, host, options);

  client.on("end", function() {
    sys.log("end event received from Redis client.");
  });

  client.on("error", function(err) {
    sys.log("Redis error: " + err.message);
    /* if this was connection refused, lets exit */
    if (err.message.match(/ECONNREFUSED/)) {
      process.exit(-1);
    }
  });

  client.on("connect", function() {
    sys.log("connected to Redis server on " +
      (config.redis.host || 'localhost') + ":" +
      Number(config.redis.port || 6379));
  });

  return client;
}

/* Trim the logs in redis, flushing any records that have been trimmed.
 * Because this relies on a few synchronous round trips to redis per logger,
 * it's run on its own interval.
 */

function trimLogs(redisClient, config) {
  var logd = config.redis.prefix || 'logd';
  var defaultSize = config.logSize['default'] || 100000;

  /* fetch a list of all of the paths to truncate */
  redisClient.smembers(logd + ':paths', function(err, paths) {
    for(var i=0; i<paths.length; i++) {
      var path = paths[i];
      var size = Number(config.logSize[path] || defaultSize);
      /* for every log, we have to truncate the main list, but we also need to
       * fetch the discarded items at the same time in order to delete the keys
       * for those messages and remove them from any sets they might have
       * belonged to
       */
      redisClient.multi()
        .sort(logd + ':log:' + path, 'BY', 'nosort', 'LIMIT', size, -1, 'GET',
              logd + ':log:' + path + ':*', 'GET', '#')
        .ltrim(logd + ':log:' + path, 0, size-1)
        .exec(function(err, ret){
          /* remove each log item from the main db and from each level, which
           * are known without fetching a list.
           */
          if (!removedItems) return;
          var removedItems = ret[0];
          var multi = redisClient.multi();

          for(var j=0; j<removedItems.length; j+=2) {
            var msg = msgpack.unpack(removedItems[i]), key = removedItems[i+1];
            multi
              .zrem(logd + ':log:' + path + ':level:' + msg.level, key)
              .zrem(logd + ':log:' + path + ':name:' + msg.name, key)
              .del(logd + ':log:' + path + ':' + key);
          }
          multi.exec(redisErrback);
      });
    }
  });
}

/* Delete a log and all support data for a given log on a path. */
function deleteLog(redisClient, config, path) {
  var logd = config.redis.prefix || 'logd';
  var base = logd + ':log:' + path;
  redisClient.lrange(base, 0, -1, function(err, keys) {
    var multi = redisClient.multi();
    for (var i=0; i<keys.length; i++) {
      var key = keys[i];
      multi.del(base + ':' + key);
    }
    multi.del(base);
    multi.del(base + ':next');
    multi.exec(redisErrback);
  });
  redisClient.lrange(base + ':' + 'names', 0, -1, function(err, keys) {
    /* FIXME: We are going to just keep level names here, which means we also
     * need to store a set of them;  similar to how we have log:names, we need
     * log:levels.  For now, we assume the python levelnames.
     */
    var multi = redisClient.multi();
    multi
      .del(base + ':level:INFO')
      .del(base + ':level:DEBUG')
      .del(base + ':level:WARNING')
      .del(base + ':level:ERROR')
      .del(base + ':level:CRITICAL');
    for (var i=0; i<keys.length; i++) {
      multi.del(base + ':name:' + keys[i]);
    }
    multi.del(base + ':names');
    multi.exec(redisErrback);
  });
}

/* send stats to graphite */

function sendStats(config, stats) {
  var port = Number(config.graphite.port || 2003)
    , host = config.graphite.host || 'localhost';

  try {
    var graphite = net.createConnection(port, host);
    graphite.addListener('error', function(connectionException){
      if (config.debug) {
        sys.log(connectionException);
      }
    });
    graphite.on('connect', function() {
      this.write(stats);
      this.end();
    });
  } catch(e) {
    if (config.debug) {
      sys.log(e);
    }
  }
}

/* read the config file and run the server */
config.configFile(process.argv[2], function (config, oldConfig) {
  if (! config.debug && debugInt) {
    clearInterval(debugInt);
    debugInt = false;
  }

  if (config.debug) {
    if (debugInt) {
      clearInterval(debugInt);
    }
    debugInt = setInterval(function () {
      sys.log("counters: " + sys.inspect(counters));
      sys.log("timers: " + sys.inspect(timers));
    }, config.debugInterval || 10000);
  }

  if (typeof config.logSize == 'undefined') {
    config.logSize = {'default': 100000};
  }

  if (typeof config.redis == 'undefined') {
    sys.log("no redis config, using defaults.");
    config.redis = {};
  }

  if (typeof config.graphite == 'undefined') {
    sys.log("no graphite config, using defaults.");
    config.graphite = {};
  }

  var redisClient = redisConnect(config);

  if (server === undefined) {
    var port = Number(config.port || 8126);
    /* listen on a datagram socket and add messages to local data structures to
     * be flushed out at a configurable interval.
     */
    server = dgram.createSocket('udp4', function (msg, rinfo) {
      messagesReceived++;
      var blob = msgpack.unpack(msg);
      if (config.debug) {
        sys.log(sys.inspect(msg));
      }

      switch (blob.id) {
        case types.LOG:
          /* TODO: do we care about this? this doubles the amt of
           * msgpack/unpack we have to do, but it allows us to always know
           * which ip sent us some information
           */
          blob.ip = rinfo.address;
          if (! logMessages[blob.path]) {
            logMessages[blob.path] = [];
          }
          logMessages[blob.path].push(blob);
          break;
        case types.COUNTER:
          /* statsd like counter */
          var sampleRate = blob.rate || 1;
          if (! counters[blob.key]) {
            counters[blob.key] = 0;
          }
          counters[blob.key] += Number((blob.value || 1) * (1 / sampleRate));
          break;
        case types.TIMER:
          /* statsd like timer */
          if (! timers[blob.key]) {
            timers[blob.key] = [];
          }
          timers[blob.key].push(blob.value);
          break;
        case types.DELETE_LOG:
          deleteLog(redisClient, blob.path);
        default: break;
      }
    });

    server.on("listening", function() {
      sys.log("logd listening on port " + port);
    });

    server.bind(port);
  }

  /* every second, print if we've received messages or not */
  var logInterval = Number(config.logInterval || 1000);

  logInt = setInterval(function() {
    if (messagesReceived != messagesReceivedPrev) {
      dmsg = messagesReceived - messagesReceivedPrev;
      messagesReceivedPrev = messagesReceived;
      sys.log("Received " + dmsg + " messages in 1s (" + messagesReceived + " total).");
    }
  }, logInterval);

  /* every second, flush local stats & messages to redis */
  var flushInterval = Number(config.flushInterval || 1000);

  flushInt = setInterval(function() {
    /* flush log messages */
    var messages, logger, size, msg;
    var allsize = Number(config.logSize['all'] || 250000);
    var logd = config.redis.prefix || 'logd';

    for (path in logMessages) {
      if (!logMessages[path] || !logMessages[path].length) continue;

      var base = logd + ':log:' + path;

      /* ids for these messages are simple monotonically increasing integers.
       * fetch the value for the next id from the database and add the cached
       * messages.
       */
      redisClient.get(base + ':next', function(base, path) {
          return function(err, next) {
            var messages = logMessages[path];
            var count = 0;
            var multi = redisClient.multi();
            next = Number(next);

            /* if there was no "next" setting, then this logger didn't exist yet.
             * add it to the list of paths and give it a next val
             */
            if (!next) {
              next = 1;
              redisClient.multi()
                .sadd('logd:paths', path)
                .set(base + ':next', next)
                .exec();
            }

            /* add the messages to the path's lists & ordered sets */
            for( ; count < messages.length; count++, next++) {
              msg = messages[count];
              msg.id = next;
              //  https://github.com/mranney/node_redis/pull/119
              //  fixed in 0.6.5
              var packed = msgpack.pack(msg);
              //var bufpacked = new Buffer(packed.length);
              //packed.copy(bufpacked)
              multi
                .set(base + ':' + next, packed)
                .lpush(base, next)
                .zadd(base + ':level:' + msg.level, -msg.time, next)
                .zadd(base + ':name:' + msg.name, -msg.time, next)
                .sadd(base + ':names', msg.name);
            }

            /* clear local cache, increment the in-redis next val, and flush */
            /*
            if (!count) {
              debugger;
            }
            */
            multi.incrby(base + ':next', count);
            multi.exec(redisErrback);
            logMessages[path] = [];
          };
        }(base, path)
      );
    }

  }, flushInterval);

  var trimInterval = Number(config.trimInterval || 10000);

  trimInt = setInterval(function() {
    trimLogs(redisClient, config);
  }, trimInterval)

  /* Every 10 seconds, flush stats to graphite.  This code is exactly
   * the same as the statsd code, as even the local storage is identical.
   */
  var statsInterval = Number(config.statsInterval || 10000);

  statsInt = setInterval(function() {
    var statString = '';
    var ts = Math.round(new Date().getTime() / 1000);
    var numStats = 0;
    var key;

    for (key in counters) {
      var value = counters[key] / (flushInterval / 1000);
      var message = 'stats.' + key + ' ' + value + ' ' + ts + "\n";
      message += 'stats.counts.' + key + ' ' + counters[key] + ' ' + ts + "\n";
      statString += message;
      counters[key] = 0;

      numStats += 1;
    }

    for (key in timers) {
      if (timers[key].length > 0) {
        var pctThreshold = config.percentThreshold || 90;
        var values = timers[key].sort(function (a,b) { return a-b; });
        var count = values.length;
        var min = values[0];
        var max = values[count - 1];

        var mean = min;
        var maxAtThreshold = max;

        if (count > 1) {
          var thresholdIndex = Math.round(((100 - pctThreshold) / 100) * count);
          var numInThreshold = count - thresholdIndex;
          values = values.slice(0, numInThreshold);
          maxAtThreshold = values[numInThreshold - 1];

          // average the remaining timings
          var sum = 0;
          for (var i = 0; i < numInThreshold; i++) {
            sum += values[i];
          }

          mean = sum / numInThreshold;
        }

        timers[key] = [];

        var message = "";
        message += 'stats.timers.' + key + '.mean ' + mean + ' ' + ts + "\n";
        message += 'stats.timers.' + key + '.upper ' + max + ' ' + ts + "\n";
        message += 'stats.timers.' + key + '.upper_' + pctThreshold + ' ' + maxAtThreshold + ' ' + ts + "\n";
        message += 'stats.timers.' + key + '.lower ' + min + ' ' + ts + "\n";
        message += 'stats.timers.' + key + '.count ' + count + ' ' + ts + "\n";
        statString += message;

        numStats += 1;
      }
    }

    statString += 'stats.numStats ' + numStats + ' ' + ts + "\n";
    if (numStats) {
      if (config.debug) {
        sys.log("Sending stats string: \n" + statString);
      }
      sendStats(config, statString);
    }

  }, statsInterval);

});

<commit_msg>check for the result of msgpack and punt if it's failed to unpack<commit_after>var dgram  = require('dgram')
  , sys    = require('sys')
  , net    = require('net')
  , msgpack = require('msgpack')
  , config = require('./config')
  , redis  = require('redis')

/* enums for message types and message levels */

var types = Object.freeze({
  LOG: 1,
  COUNTER: 2,
  TIMER: 3,
  DELETE_LOG: 4,
});

var levels = Object.freeze({
  DEBUG: 10,
  INFO: 20,
  WARNING: 30,
  ERROR: 40,
  FATAL: 50
});

var messagesReceived = 0;
var messagesReceivedPrev = 0;
var logMessages = {};
var counters = {};
var timers = {};
var debugInt, flushInt, logInt, trimInt, statsInt, server;

function redisErrback(err, ret) {
  if (err) {
    sys.log("redis error: " + err);
  }
}

/* Connect to redis, using the configuration options provided, falling
 * back on sane defaults.  Sets a few message handlers to deal with errors
 * and report the status of the connection.
 */

function redisConnect(config) {
  var port = Number(config.redis.port || 6379),
      host = config.redis.host || "localhost",
      options = config.redisOptions || {};

  var client = redis.createClient(port, host, options);

  client.on("end", function() {
    sys.log("end event received from Redis client.");
  });

  client.on("error", function(err) {
    sys.log("Redis error: " + err.message);
    /* if this was connection refused, lets exit */
    if (err.message.match(/ECONNREFUSED/)) {
      process.exit(-1);
    }
  });

  client.on("connect", function() {
    sys.log("connected to Redis server on " +
      (config.redis.host || 'localhost') + ":" +
      Number(config.redis.port || 6379));
  });

  return client;
}

/* Trim the logs in redis, flushing any records that have been trimmed.
 * Because this relies on a few synchronous round trips to redis per logger,
 * it's run on its own interval.
 */

function trimLogs(redisClient, config) {
  var logd = config.redis.prefix || 'logd';
  var defaultSize = config.logSize['default'] || 100000;

  /* fetch a list of all of the paths to truncate */
  redisClient.smembers(logd + ':paths', function(err, paths) {
    for(var i=0; i<paths.length; i++) {
      var path = paths[i];
      var size = Number(config.logSize[path] || defaultSize);
      /* for every log, we have to truncate the main list, but we also need to
       * fetch the discarded items at the same time in order to delete the keys
       * for those messages and remove them from any sets they might have
       * belonged to
       */
      redisClient.multi()
        .sort(logd + ':log:' + path, 'BY', 'nosort', 'LIMIT', size, -1, 'GET',
              logd + ':log:' + path + ':*', 'GET', '#')
        .ltrim(logd + ':log:' + path, 0, size-1)
        .exec(function(err, ret){
          /* remove each log item from the main db and from each level, which
           * are known without fetching a list.
           */
          if (!removedItems) return;
          var removedItems = ret[0];
          var multi = redisClient.multi();

          for(var j=0; j<removedItems.length; j+=2) {
            var msg = msgpack.unpack(removedItems[i]), key = removedItems[i+1];
            multi
              .zrem(logd + ':log:' + path + ':level:' + msg.level, key)
              .zrem(logd + ':log:' + path + ':name:' + msg.name, key)
              .del(logd + ':log:' + path + ':' + key);
          }
          multi.exec(redisErrback);
      });
    }
  });
}

/* Delete a log and all support data for a given log on a path. */
function deleteLog(redisClient, config, path) {
  var logd = config.redis.prefix || 'logd';
  var base = logd + ':log:' + path;
  redisClient.lrange(base, 0, -1, function(err, keys) {
    var multi = redisClient.multi();
    for (var i=0; i<keys.length; i++) {
      var key = keys[i];
      multi.del(base + ':' + key);
    }
    multi.del(base);
    multi.del(base + ':next');
    multi.exec(redisErrback);
  });
  redisClient.lrange(base + ':' + 'names', 0, -1, function(err, keys) {
    /* FIXME: We are going to just keep level names here, which means we also
     * need to store a set of them;  similar to how we have log:names, we need
     * log:levels.  For now, we assume the python levelnames.
     */
    var multi = redisClient.multi();
    multi
      .del(base + ':level:INFO')
      .del(base + ':level:DEBUG')
      .del(base + ':level:WARNING')
      .del(base + ':level:ERROR')
      .del(base + ':level:CRITICAL');
    for (var i=0; i<keys.length; i++) {
      multi.del(base + ':name:' + keys[i]);
    }
    multi.del(base + ':names');
    multi.exec(redisErrback);
  });
}

/* send stats to graphite */

function sendStats(config, stats) {
  var port = Number(config.graphite.port || 2003)
    , host = config.graphite.host || 'localhost';

  try {
    var graphite = net.createConnection(port, host);
    graphite.addListener('error', function(connectionException){
      if (config.debug) {
        sys.log(connectionException);
      }
    });
    graphite.on('connect', function() {
      this.write(stats);
      this.end();
    });
  } catch(e) {
    if (config.debug) {
      sys.log(e);
    }
  }
}

/* read the config file and run the server */
config.configFile(process.argv[2], function (config, oldConfig) {
  if (!config.debug && debugInt) {
    clearInterval(debugInt);
    debugInt = false;
  }

  if (config.debug) {
    if (debugInt) {
      clearInterval(debugInt);
    }
    debugInt = setInterval(function () {
      sys.log("counters: " + sys.inspect(counters));
      sys.log("timers: " + sys.inspect(timers));
    }, config.debugInterval || 10000);
  }

  if (typeof config.logSize == 'undefined') {
    config.logSize = {'default': 100000};
  }

  if (typeof config.redis == 'undefined') {
    sys.log("no redis config, using defaults.");
    config.redis = {};
  }

  if (typeof config.graphite == 'undefined') {
    sys.log("no graphite config, using defaults.");
    config.graphite = {};
  }

  var redisClient = redisConnect(config);

  if (server === undefined) {
    var port = Number(config.port || 8126);
    /* listen on a datagram socket and add messages to local data structures to
     * be flushed out at a configurable interval.
     */
    server = dgram.createSocket('udp4', function (msg, rinfo) {
      messagesReceived++;
      var blob = msgpack.unpack(msg);
      if (!blob) {
        sys.log("Error with message " + msg);
        return;
      }
      if (config.debug) {
        sys.log(sys.inspect(msg));
      }

      switch (blob.id) {
        case types.LOG:
          /* TODO: do we care about this? this doubles the amt of
           * msgpack/unpack we have to do, but it allows us to always know
           * which ip sent us some information
           */
          blob.ip = rinfo.address;
          if (! logMessages[blob.path]) {
            logMessages[blob.path] = [];
          }
          logMessages[blob.path].push(blob);
          break;
        case types.COUNTER:
          /* statsd like counter */
          var sampleRate = blob.rate || 1;
          if (! counters[blob.key]) {
            counters[blob.key] = 0;
          }
          counters[blob.key] += Number((blob.value || 1) * (1 / sampleRate));
          break;
        case types.TIMER:
          /* statsd like timer */
          if (! timers[blob.key]) {
            timers[blob.key] = [];
          }
          timers[blob.key].push(blob.value);
          break;
        case types.DELETE_LOG:
          deleteLog(redisClient, blob.path);
        default: break;
      }
    });

    server.on("listening", function() {
      sys.log("logd listening on port " + port);
    });

    server.bind(port);
  }

  /* every second, print if we've received messages or not */
  var logInterval = Number(config.logInterval || 1000);

  logInt = setInterval(function() {
    if (messagesReceived != messagesReceivedPrev) {
      dmsg = messagesReceived - messagesReceivedPrev;
      messagesReceivedPrev = messagesReceived;
      sys.log("Received " + dmsg + " messages in 1s (" + messagesReceived + " total).");
    }
  }, logInterval);

  /* every second, flush local stats & messages to redis */
  var flushInterval = Number(config.flushInterval || 1000);

  flushInt = setInterval(function() {
    /* flush log messages */
    var messages, logger, size, msg;
    var allsize = Number(config.logSize['all'] || 250000);
    var logd = config.redis.prefix || 'logd';

    for (path in logMessages) {
      if (!logMessages[path] || !logMessages[path].length) continue;

      var base = logd + ':log:' + path;

      /* ids for these messages are simple monotonically increasing integers.
       * fetch the value for the next id from the database and add the cached
       * messages.
       */
      redisClient.get(base + ':next', function(base, path) {
          return function(err, next) {
            var messages = logMessages[path];
            var count = 0;
            var multi = redisClient.multi();
            next = Number(next);

            /* if there was no "next" setting, then this logger didn't exist yet.
             * add it to the list of paths and give it a next val
             */
            if (!next) {
              next = 1;
              redisClient.multi()
                .sadd('logd:paths', path)
                .set(base + ':next', next)
                .exec();
            }

            /* add the messages to the path's lists & ordered sets */
            for( ; count < messages.length; count++, next++) {
              msg = messages[count];
              msg.id = next;
              //  https://github.com/mranney/node_redis/pull/119
              //  fixed in 0.6.5
              var packed = msgpack.pack(msg);
              //var bufpacked = new Buffer(packed.length);
              //packed.copy(bufpacked)
              multi
                .set(base + ':' + next, packed)
                .lpush(base, next)
                .zadd(base + ':level:' + msg.level, -msg.time, next)
                .zadd(base + ':name:' + msg.name, -msg.time, next)
                .sadd(base + ':names', msg.name);
            }

            /* clear local cache, increment the in-redis next val, and flush */
            /*
            if (!count) {
              debugger;
            }
            */
            multi.incrby(base + ':next', count);
            multi.exec(redisErrback);
            logMessages[path] = [];
          };
        }(base, path)
      );
    }

  }, flushInterval);

  var trimInterval = Number(config.trimInterval || 10000);

  trimInt = setInterval(function() {
    trimLogs(redisClient, config);
  }, trimInterval)

  /* Every 10 seconds, flush stats to graphite.  This code is exactly
   * the same as the statsd code, as even the local storage is identical.
   */
  var statsInterval = Number(config.statsInterval || 10000);

  statsInt = setInterval(function() {
    var statString = '';
    var ts = Math.round(new Date().getTime() / 1000);
    var numStats = 0;
    var key;

    for (key in counters) {
      var value = counters[key] / (flushInterval / 1000);
      var message = 'stats.' + key + ' ' + value + ' ' + ts + "\n";
      message += 'stats.counts.' + key + ' ' + counters[key] + ' ' + ts + "\n";
      statString += message;
      counters[key] = 0;

      numStats += 1;
    }

    for (key in timers) {
      if (timers[key].length > 0) {
        var pctThreshold = config.percentThreshold || 90;
        var values = timers[key].sort(function (a,b) { return a-b; });
        var count = values.length;
        var min = values[0];
        var max = values[count - 1];

        var mean = min;
        var maxAtThreshold = max;

        if (count > 1) {
          var thresholdIndex = Math.round(((100 - pctThreshold) / 100) * count);
          var numInThreshold = count - thresholdIndex;
          values = values.slice(0, numInThreshold);
          maxAtThreshold = values[numInThreshold - 1];

          // average the remaining timings
          var sum = 0;
          for (var i = 0; i < numInThreshold; i++) {
            sum += values[i];
          }

          mean = sum / numInThreshold;
        }

        timers[key] = [];

        var message = "";
        message += 'stats.timers.' + key + '.mean ' + mean + ' ' + ts + "\n";
        message += 'stats.timers.' + key + '.upper ' + max + ' ' + ts + "\n";
        message += 'stats.timers.' + key + '.upper_' + pctThreshold + ' ' + maxAtThreshold + ' ' + ts + "\n";
        message += 'stats.timers.' + key + '.lower ' + min + ' ' + ts + "\n";
        message += 'stats.timers.' + key + '.count ' + count + ' ' + ts + "\n";
        statString += message;

        numStats += 1;
      }
    }

    statString += 'stats.numStats ' + numStats + ' ' + ts + "\n";
    if (numStats) {
      if (config.debug) {
        sys.log("Sending stats string: \n" + statString);
      }
      sendStats(config, statString);
    }

  }, statsInterval);

});

<|endoftext|>


<commit_before>'use strict';

/**
 * @file
 * Main component for showing searchstring as buttons
 *
 * Properties:
 * query: an array of query elements. Only supports string elements for now.
 * change optional callback function for when the input field is updated
 */

import React, {PropTypes} from 'react';
import ReactDOM from 'react-dom';
import _ from 'lodash';
import TokenList from '../TokenList/TokenList.component.js';
import {updateQueryFromString} from '../../../utils/QueryString.util';

const TokenSearchField = React.createClass({
  displayName: 'TokenSearchField.component',
  propTypes: {
    change: PropTypes.func,
    focus: PropTypes.func,
    pending: PropTypes.bool,
    placeholder: PropTypes.string,
    query: PropTypes.array.isRequired,
    translations: PropTypes.object,
    update: PropTypes.func.isRequired
  },

  getInitialState() {
    return {
      value: '',
      hasFocus: false,
      text: this.getQueryTexts()
    };
  },

  componentDidMount() {
    this.hasScrolled = false;
    if (window) {
      window.addEventListener('touchmove', () => {
        if (!this.hasScrolled) {
          this.hasScrolled = true;
          this.onBlur();
        }
      });
    }
  },

  hasScrolled: false,

  removeElement(element) {
    let query = _.remove(this.props.query, (queryObject)=> queryObject !== element);
    const text = query.map((e)=> e.value).join(' ');
    this.props.update(query);
    this.setState({text: text});
  },

  onSubmit(event) {
    // make sure form is not submitted, it is handled with js
    // @todo implement fallback for when js is failing
    event.preventDefault();

    // removing focus from the textfield
    this.onBlur();
    const focus = false;
    this.props.focus(focus);

    // update query with the updated text string
    let text = this.state.text && this.state.text.trim() || '';
    let query = updateQueryFromString(text, this.props.query);

    // Send updated query to parent component
    this.props.update(query);

    // Update local state: remove focus and empty textfield
    this.setState({
      text: '',
      hasFocus: focus
    });
  },

  getQueryTexts() {
    return this.props.query.map((element)=> element.value).join(' ');
  },

  setFocus(state) {
    // scroll to searchfield
    location.href = '#mainsearch';
    // remove url hash again to keep url neat
    history.replaceState({}, document.title, '/');

    this.hasScrolled = false;
    let text = state && this.getQueryTexts() || this.state.text;
    this.props.focus(state); // mismatch between this and the below hasFocus value
    this.setState({hasFocus: state, text});
  },

  onBlur() {
    ReactDOM.findDOMNode(this.refs.searchfield).blur();
  },

  onChange(event) {
    let text = event.target.value;
    if (!this.state.hasFocus) {
      text = this.getQueryTexts() + ' ' + text;
    }
    this.setState({text});
    if (this.props.change) {
      this.props.change(event.target.value);
    }
  },

  onKey(event) {
    if (event.key && event.key === 'Escape') {
      this.onBlur();
      this.setFocus(false);
    }
  },

  render() {
    const {hasFocus, text} = this.state;
    const {query, pending} = this.props;
    const tokenClasses = !hasFocus && 'tokens-wrapper' || 'tokens-wrapper hide';
    const spinnerClass = pending ? 'token-searchfield--spinner pending' : 'token-searchfield--spinner';

    return (

        <form onSubmit={this.onSubmit} >

                      <TokenList query={query} remove={this.removeElement} translations={this.props.translations} />

                  <input className='searchfield'
                         onChange={this.onChange}
                         onClick={this.setFocus.bind(this, true)}
                         onFocus={this.setFocus.bind(this, true)}
                         placeholder={this.props.placeholder}
                         ref='searchfield'
                         type='text'
                         value={text || ''}
                  />
                  <span className={`${spinnerClass}`} />

                  <input className='button postfix' onClick={this.onSubmit} type='submit' value='Søg' />

        </form>

    );
  }
});

export default TokenSearchField;
<commit_msg>Accumulated commit of the following from branch 'origin/ready/mra':<commit_after>'use strict';

/**
 * @file
 * Main component for showing searchstring as buttons
 *
 * Properties:
 * query: an array of query elements. Only supports string elements for now.
 * change optional callback function for when the input field is updated
 */

import React, {PropTypes} from 'react';
import ReactDOM from 'react-dom';
import _ from 'lodash';
import TokenList from '../TokenList/TokenList.component.js';
import {updateQueryFromString} from '../../../utils/QueryString.util';

const TokenSearchField = React.createClass({
  displayName: 'TokenSearchField.component',
  propTypes: {
    change: PropTypes.func,
    focus: PropTypes.func,
    pending: PropTypes.bool,
    placeholder: PropTypes.string,
    query: PropTypes.array.isRequired,
    translations: PropTypes.object,
    update: PropTypes.func.isRequired
  },

  getInitialState() {
    return {
      value: '',
      hasFocus: false,
      text: this.getQueryTexts()
    };
  },

  componentDidMount() {
    this.hasScrolled = false;
    if (window) {
      window.addEventListener('touchmove', () => {
        if (!this.hasScrolled) {
          this.hasScrolled = true;
          this.onBlur();
        }
      });
    }
  },

  hasScrolled: false,

  removeElement(element) {
    let query = _.remove(this.props.query, (queryObject)=> queryObject !== element);
    const text = query.map((e)=> e.value).join(' ');
    this.props.update(query);
    this.setState({text: text});
  },

  onSubmit(event) {
    // make sure form is not submitted, it is handled with js
    // @todo implement fallback for when js is failing
    event.preventDefault();

    // removing focus from the textfield
    this.onBlur();
    const focus = false;
    this.props.focus(focus);

    // update query with the updated text string
    let text = this.state.text && this.state.text.trim() || '';
    let query = updateQueryFromString(text, this.props.query);

    // Send updated query to parent component
    this.props.update(query);

    // Update local state: remove focus and empty textfield
    this.setState({
      text: '',
      hasFocus: focus
    });
  },

  getQueryTexts() {
    return this.props.query.map((element)=> element.value).join(' ');
  },

  setFocus(state) {
    this.hasScrolled = false;
    let text = state && this.getQueryTexts() || this.state.text;
    this.props.focus(state); // mismatch between this and the below hasFocus value
    this.setState({hasFocus: state, text});
  },

  onBlur() {
    ReactDOM.findDOMNode(this.refs.searchfield).blur();
  },

  onChange(event) {
    let text = event.target.value;
    if (!this.state.hasFocus) {
      text = this.getQueryTexts() + ' ' + text;
    }
    this.setState({text});
    if (this.props.change) {
      this.props.change(event.target.value);
    }
  },

  onKey(event) {
    if (event.key && event.key === 'Escape') {
      this.onBlur();
      this.setFocus(false);
    }
  },

  render() {
    const {hasFocus, text} = this.state;
    const {query, pending} = this.props;
    const tokenClasses = !hasFocus && 'tokens-wrapper' || 'tokens-wrapper hide';
    const spinnerClass = pending ? 'token-searchfield--spinner pending' : 'token-searchfield--spinner';

    return (

        <form onSubmit={this.onSubmit} >

                      <TokenList query={query} remove={this.removeElement} translations={this.props.translations} />

                  <input className='searchfield'
                         onChange={this.onChange}
                         onClick={this.setFocus.bind(this, true)}
                         onFocus={this.setFocus.bind(this, true)}
                         placeholder={this.props.placeholder}
                         ref='searchfield'
                         type='text'
                         value={text || ''}
                  />
                  <span className={`${spinnerClass}`} />

                  <input className='button postfix' onClick={this.onSubmit} type='submit' value='Søg' />

        </form>

    );
  }
});

export default TokenSearchField;
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Expedia, Inc.
 *
 *         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.
 */
import alertsStore from '../../../alerts/stores/serviceAlertsStore';

export class AlertsTabStateStore {
    search = null;
    isAvailable = false;

    init(search) {
        // initialize observables using search object
        // check if for the given search context tab should be available
        this.search = search;

        // check all keys except time
        // eslint-disable-next-line no-unused-vars
        const {time, tabId, ...kv} =  search;
        const keys = Object.keys(kv);
        this.isAvailable = keys.length && keys.every(key => key === 'serviceName' || key === 'operationName');
    }

    fetch() {
        alertsStore.fetchServiceAlerts(this.search.serviceName, 300000, '12h');
        return alertsStore;
    }
}

export default new AlertsTabStateStore();
<commit_msg>additional space to create a new version of file (#298)<commit_after>/*
 * Copyright 2017 Expedia, Inc.
 *
 *         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.
 */

import alertsStore from '../../../alerts/stores/serviceAlertsStore';

export class AlertsTabStateStore {
    search = null;
    isAvailable = false;

    init(search) {
        // initialize observables using search object
        // check if for the given search context tab should be available
        this.search = search;

        // check all keys except time
        // eslint-disable-next-line no-unused-vars
        const {time, tabId, ...kv} =  search;
        const keys = Object.keys(kv);
        this.isAvailable = keys.length && keys.every(key => key === 'serviceName' || key === 'operationName');
    }

    fetch() {
        alertsStore.fetchServiceAlerts(this.search.serviceName, 300000, '12h');
        return alertsStore;
    }
}

export default new AlertsTabStateStore();
<|endoftext|>


<commit_before>'use strict';

angular.module('myApp.apiService', [])
    .factory('Api', ['$http',
        function ($http) {
          return {

            env: 'production',

            options: {
              development: { url: "http://offerfans.ngrok.com", version: 'v1' },
              staging:     { url: "https://stg.offerfans.com", version: 'v1' },
              production:  { url: "https://www.offerfans.com", version: 'v1' }
            },

            currentEnv: function()  {
              return this.env;
            },

            buildUrl: function(path) {

              if (!this.options[ this.env ]) {
                this.env = 'production';
              }

              var url = this.options[this.env]['url'] + '/api/' + this.options[this.env]['version'] + path;

              console.log("API url: "+url);
              return url;
            },

            login: function(user, onSuccess, onFailure) {
              $http.post(this.buildUrl("/auth/login"), user, {timeout: 3000})
                   .success(onSuccess)
                   .error(onFailure);
            },

            redeem: function(code, onSuccess, onFailure) {
              var options = {
                  headers: {
                      'Access-Token' : window.localStorage.getItem("access_token")
                  },
                  timeout: 3000
              }

              // put access_token in header
              $http.put(this.buildUrl("/redeem/"+code), {}, options)
                   .success(onSuccess)
                   .error(onFailure);
            }
          }
        }]);
<commit_msg>Increase api connection timeout to 5s<commit_after>'use strict';

angular.module('myApp.apiService', [])
    .factory('Api', ['$http',
        function ($http) {
          return {

            env: 'production',

            options: {
              development: { url: "http://offerfans.ngrok.com", version: 'v1' },
              staging:     { url: "https://stg.offerfans.com", version: 'v1' },
              production:  { url: "https://www.offerfans.com", version: 'v1' }
            },

            currentEnv: function()  {
              return this.env;
            },

            buildUrl: function(path) {

              if (!this.options[ this.env ]) {
                this.env = 'production';
              }

              var url = this.options[this.env]['url'] + '/api/' + this.options[this.env]['version'] + path;

              console.log("API url: "+url);
              return url;
            },

            login: function(user, onSuccess, onFailure) {
              $http.post(this.buildUrl("/auth/login"), user, {timeout: 5000})
                   .success(onSuccess)
                   .error(onFailure);
            },

            redeem: function(code, onSuccess, onFailure) {
              var options = {
                  headers: {
                      'Access-Token' : window.localStorage.getItem("access_token")
                  },
                  timeout: 5000
              }

              // put access_token in header
              $http.put(this.buildUrl("/redeem/"+code), {}, options)
                   .success(onSuccess)
                   .error(onFailure);
            }
          }
        }]);
<|endoftext|>


<commit_before>angular.module('c42-ionic.controllers', [])

.controller('HomeCtrl', ['$scope', 'config', 'local_settings', 'c42Api','calendarFilter', '$window', function($scope,config, local_settings, c42Api, calendarFilter, $window) {
  var options = {
    // As we want to show quite some markers on the map, this is now set to 100.
    // If the markers and events in the list are pulled of different API calls this could be set to 10
    // Also, we should move the client side filtering then to the API
    limit: 100,
    offset: 0,
  };

  var _resetOffset = function () {
    options.offset = 0;
    $scope.events = null;
  };

  $scope.onclick = function (eventId) {
    var href="#/tab/event/" + eventId;
    $window.location.href = href;
  };

  $scope.mapConfig = config.initialConfig.mapDefaults;

  // @TODO: Add this to the resolve in the way that is filtered before of being rendered
  // @TODO: Get it form the BE
  $scope.$on('$ionicView.enter', function() {
    if($scope.events){
      var filters = calendarFilter.getFilters();
      // Checking if the event contains any calendar that is selected in the "filter calendars"
      $scope.events.forEach(function(event,idx, eventsList){
        if(event.__calendars.length && filters.length){
          eventsList[idx].filtererdOut = event.__calendars.some(function(calendar){
            return !calendarFilter.inFilter(calendar.id);
          });
        }else{
          eventsList[idx].filtererdOut = false;
        }
      });
    }
  });

  $scope.doRefresh = function () {
    // @fixme: although we immediatly broadcast this, the arrow can still be briefly seen after loading
    $scope.$broadcast('scroll.refreshComplete');
    _resetOffset();
    $scope.loadMore();
  };

  $scope.loadMore = function () {
    c42Api.getEvents(options, function(events){
        $scope.$apply(function () {
            $scope.events = $scope.events ? $scope.events.concat(events) : events;
        });
        options.offset += $scope.events.length;
        // Notify that the infinite loading is complete
        $scope.$broadcast('scroll.infiniteScrollComplete');
    });
  };

}])

.controller('InterestsCtrl', function($scope, c42Api, calendarFilter) {
  // $scope.calendars = [];
  $scope.data = {
    badgeCount : 1
  };
  if(!$scope.calendars){
    c42Api.getCalendars(function(calendars){
      $scope.calendars = calendars;
      $scope.data = {
        badgeCount : calendars.length
      };
    });
  }

  $scope.inFilter = function(calendar_id){
    return calendarFilter.inFilter(calendar_id);
  };

  $scope.saveFilter = function(checked, calendar_id){
    if(checked){
      calendarFilter.addFilter(calendar_id);
    }else{
      calendarFilter.removeFilter(calendar_id);
    }
  };
})

.controller('EventDetailCtrl', ['$scope', '$stateParams', 'c42Api', function($scope, $stateParams, c42Api) {
  // Map Options
  $scope.mapOptions ={
    disableDefaultUI:true,
    panControl: false,
    draggable: false
  };

  $scope.mapOptionsHero ={
    disableDefaultUI:true,
    tilt:45,
    panControl: false,
    draggable: false,
    mapTypeId: google.maps.MapTypeId.SATELLITE
  };

  // toggling items
  $scope.toggleItem= function(item) {
    if ($scope.isItemShown(item)) {
      $scope.shownItem = null;
    } else {
      $scope.shownItem = item;
    }
  };
  $scope.isItemShown = function(item) {
    return $scope.shownItem === item;
  };

  $scope.changeAttending = function() {
    $scope.attending = !$scope.attending;
    $scope.event.rsvp_status = $scope.attending ? 'attending' : 'not_attending';
    c42Api.updateEventFields($scope.event, ['rsvp_status'], function (resp) {
      console.warn(resp);
    });
  };

  // BEGIN setting event data
  c42Api.getEventById($stateParams.eventId, function (event) {
    $scope.event = event;
    $scope.attending = event.rsvp_status == 'attending';
    if (event.start_location.geo) {
      // @todo: this has actually not been tested on any device yet, we might need to add cordova-plugin-inappbrowser
      // @todo: a different link should be called depending on whether you're on Android or iOS
      //        - https://gist.github.com/mrzmyr/977fc7d8bee58db9d96f
      $scope.mapsUrl = "comgooglemaps://?daddr="+event.start_location.text; // Android
    }
  });
  // END setting event data
}])

.controller('AccountCtrl', function($scope) {
  $scope.settings = {
    enableFriends: true
  };
});
<commit_msg>optimise event pane anitmation by waiting setting scope on ionicView.afterEnter<commit_after>angular.module('c42-ionic.controllers', [])

.controller('HomeCtrl', ['$scope', 'config', 'local_settings', 'c42Api','calendarFilter', '$window', function($scope,config, local_settings, c42Api, calendarFilter, $window) {
  var options = {
    // As we want to show quite some markers on the map, this is now set to 100.
    // If the markers and events in the list are pulled of different API calls this could be set to 10
    // Also, we should move the client side filtering then to the API
    limit: 100,
    offset: 0,
  };

  var _resetOffset = function () {
    options.offset = 0;
    $scope.events = null;
  };

  $scope.onclick = function (eventId) {
    var href="#/tab/event/" + eventId;
    $window.location.href = href;
  };

  $scope.mapConfig = config.initialConfig.mapDefaults;

  // @TODO: Add this to the resolve in the way that is filtered before of being rendered
  // @TODO: Get it form the BE
  $scope.$on('$ionicView.enter', function() {
    if($scope.events){
      var filters = calendarFilter.getFilters();
      // Checking if the event contains any calendar that is selected in the "filter calendars"
      $scope.events.forEach(function(event,idx, eventsList){
        if(event.__calendars.length && filters.length){
          eventsList[idx].filtererdOut = event.__calendars.some(function(calendar){
            return !calendarFilter.inFilter(calendar.id);
          });
        }else{
          eventsList[idx].filtererdOut = false;
        }
      });
    }
  });

  $scope.doRefresh = function () {
    // @fixme: although we immediatly broadcast this, the arrow can still be briefly seen after loading
    $scope.$broadcast('scroll.refreshComplete');
    _resetOffset();
    $scope.loadMore();
  };

  $scope.loadMore = function () {
    c42Api.getEvents(options, function(events){
        $scope.$apply(function () {
            $scope.events = $scope.events ? $scope.events.concat(events) : events;
        });
        options.offset += $scope.events.length;
        // Notify that the infinite loading is complete
        $scope.$broadcast('scroll.infiniteScrollComplete');
    });
  };

}])

.controller('InterestsCtrl', function($scope, c42Api, calendarFilter) {
  // $scope.calendars = [];
  $scope.data = {
    badgeCount : 1
  };
  if(!$scope.calendars){
    c42Api.getCalendars(function(calendars){
      $scope.calendars = calendars;
      $scope.data = {
        badgeCount : calendars.length
      };
    });
  }

  $scope.inFilter = function(calendar_id){
    return calendarFilter.inFilter(calendar_id);
  };

  $scope.saveFilter = function(checked, calendar_id){
    if(checked){
      calendarFilter.addFilter(calendar_id);
    }else{
      calendarFilter.removeFilter(calendar_id);
    }
  };
})

.controller('EventDetailCtrl', ['$scope', '$stateParams', 'c42Api', function($scope, $stateParams, c42Api) {
  // Map Options
  $scope.mapOptions ={
    disableDefaultUI:true,
    panControl: false,
    draggable: false
  };

  $scope.mapOptionsHero ={
    disableDefaultUI:true,
    panControl: false,
    draggable: false,
    mapTypeId: google.maps.MapTypeId.SATELLITE
  };

  // toggling items
  $scope.toggleItem= function(item) {
    if ($scope.isItemShown(item)) {
      $scope.shownItem = null;
    } else {
      $scope.shownItem = item;
    }
  };
  $scope.isItemShown = function(item) {
    return $scope.shownItem === item;
  };

  $scope.changeAttending = function() {
    $scope.attending = !$scope.attending;
    $scope.event.rsvp_status = $scope.attending ? 'attending' : 'not_attending';
    c42Api.updateEventFields($scope.event, ['rsvp_status'], function (resp) {
      console.warn(resp);
    });
  };

  var _setEventScope = function () {
    c42Api.getEventById($stateParams.eventId, function (event) {
      $scope.event = event;
      $scope.attending = event.rsvp_status == 'attending';
      if (event.start_location.geo) {
        // @todo: this has actually not been tested on any device yet, we might need to add cordova-plugin-inappbrowser
        // @todo: a different link should be called depending on whether you're on Android or iOS
        //        - https://gist.github.com/mrzmyr/977fc7d8bee58db9d96f
        $scope.mapsUrl = "comgooglemaps://?daddr="+event.start_location.text; // Android
      }
    });
  };

  $scope.$on('$ionicView.afterEnter', function(){
    _setEventScope();
  });

}])

.controller('AccountCtrl', function($scope) {
  $scope.settings = {
    enableFriends: true
  };
});
<|endoftext|>


<commit_before>angular.module('citizen-engagement.controllers', [])

/*
 * TO DO : GUZI
 * - /:id
 * - filter criteria (lvl 1 -> me)
 * - filter criteria (lvl 2 -> search)
 * - pagination filter
 * - handle actions
 *
 */

.controller('UserController', function($scope, $http) {
           $scope.data = [
			{ firstName: "John", lastName: "Doe" },
			{ firstName: "John", lastName: "Smith" },
			{ firstName: "David", lastName: "Lowe" },
			{ firstName: "Mark", lastName: "Holloway" }
		];
})

.controller('IssuesCtrl', function($scope, $http, apiUrl) {
    $scope.issues = {};

    $http({
        method: 'GET',
        url: apiUrl + '/issues',
        headers: {
            'x-pagination': '0;20',
        }
    })
    .success(function(issues) {
        $scope.issues = issues;
    });

    $scope.filterIssues = function() {

        // Show a loading message if the request takes too long.
        $ionicLoading.show({
        template: 'Logging in...',
        delay: 750
        });

        $http({
            method: 'GET',
            url: apiUrl + '/issues',
            headers: {
            'Content-Type': 'application/json',
            'x-pagination': '0;20',
            },
            data: {
                //XX
            }
    }).then(
        function(issues) {
            $ionicLoading.hide();
            // necessary? // Go to the issue list tab.
            //$state.go('tab.myIssues');
        },
        function() {
            // If an error occurs, hide the loading message and show an error message.
            $ionicLoading.hide();
            $scope.error = 'Could not get any Issues.';
      }
    )
    }
})

.controller('MyIssuesCtrl', function($scope, $http, apiUrl) {
    $scope.issues = {};
    $http({
        method: 'GET',
        url: apiUrl + '/me/issues',
        headers: {
            'x-pagination': '0;20',
            'x-user-id': AuthService.currentUserId
        }
    })
    .success(function(issues) {
        $scope.issues = issues;
    });
})

.controller('UsersCtrl', function($scope, $http, apiUrl) {
    $scope.issues = {};
    $http({
        method: 'GET',
        url: apiUrl + '/users',
        headers: {
            'x-pagination': '0;10',
            'x-user-id': AuthService.currentUserId,
        }
    })
    .success(function(issues) {
        $scope.issues = issues;
    });
})

.controller('IssueTypesCtrl', function($scope, $http, apiUrl) {
    $scope.issues = {};
    $http({
        method: 'GET',
        url: apiUrl + '/issueTypes',
        headers: {
            'x-pagination': '0;20'
        }
    })
    .success(function(issues) {
        $scope.issues = issues;
    });
})

;
<commit_msg>remove obsolete controller<commit_after>angular.module('citizen-engagement.controllers', [])

/*
 * TO DO : GUZI
 * - /:id
 * - filter criteria (lvl 1 -> me)
 * - filter criteria (lvl 2 -> search)
 * - pagination filter
 * - handle actions
 *
 */

.controller('IssuesCtrl', function($scope, $http, apiUrl) {
    $scope.issues = {};

    $http({
        method: 'GET',
        url: apiUrl + '/issues',
        headers: {
            'x-pagination': '0;20',
        }
    })
    .success(function(issues) {
        $scope.issues = issues;
    });

    $scope.filterIssues = function() {

        // Show a loading message if the request takes too long.
        $ionicLoading.show({
        template: 'Logging in...',
        delay: 750
        });

        $http({
            method: 'GET',
            url: apiUrl + '/issues',
            headers: {
            'Content-Type': 'application/json',
            'x-pagination': '0;20',
            },
            data: {
                //XX
            }
    }).then(
        function(issues) {
            $ionicLoading.hide();
            // necessary? // Go to the issue list tab.
            //$state.go('tab.myIssues');
        },
        function() {
            // If an error occurs, hide the loading message and show an error message.
            $ionicLoading.hide();
            $scope.error = 'Could not get any Issues.';
      }
    )
    }
})

.controller('MyIssuesCtrl', function($scope, $http, apiUrl) {
    $scope.issues = {};
    $http({
        method: 'GET',
        url: apiUrl + '/me/issues',
        headers: {
            'x-pagination': '0;20',
            'x-user-id': AuthService.currentUserId
        }
    })
    .success(function(issues) {
        $scope.issues = issues;
    });
})

.controller('UsersCtrl', function($scope, $http, apiUrl) {
    $scope.issues = {};
    $http({
        method: 'GET',
        url: apiUrl + '/users',
        headers: {
            'x-pagination': '0;10',
            'x-user-id': AuthService.currentUserId,
        }
    })
    .success(function(issues) {
        $scope.issues = issues;
    });
})

.controller('IssueTypesCtrl', function($scope, $http, apiUrl) {
    $scope.issues = {};
    $http({
        method: 'GET',
        url: apiUrl + '/issueTypes',
        headers: {
            'x-pagination': '0;20'
        }
    })
    .success(function(issues) {
        $scope.issues = issues;
    });
})

;
<|endoftext|>