<commit_before>// *************************************************************************
// Copyright (c) 2014, SUSE LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of SUSE LLC nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// *************************************************************************
//
// html.js - functions that generate HTML source code
//
"use strict";

define ([
    'cf',
    'current-user',
    'lib',
    'app/lib',
    'target'
], function (
    cf,
    currentUser,
    lib,
    appLib,
    target
) {
    var
        //
        // "Your choice" section at the bottom - shared by all target types
        //
        yourChoice = function () {
            return '
Your choice: <input name="sel" size=3 maxlength=2> ' +
                   '<input id="submitButton" type="submit" value="Submit">

'
        },
        //
        // miniMenu is shared by dform and dbrowser
        //
        miniMenu = function (mm) {
            // mm is the dbrowser miniMenu object
            var len = mm.entries.length,
                entry,
                i,
                r;
            console.log("miniMenu is ", mm);
            console.log("miniMenu length is " + len);
            if (len > 0) {
                r = 'Menu:        ';
                for (i = 0; i < len; i += 1) {
                    //console.log("i === " + i);
                    console.log("Attempting to pull target " + mm.entries[i] + " from miniMenu");
                    entry = target.pull(mm.entries[i]);
                    if (lib.privCheck(entry.aclProfile)) {
                        r += i + '. ' + entry.menuText + '  ';
                    }
                }
                r += 'X. ' + mm.back[0];
            } else {
                r = mm.back[0];
            }
            return r;
        },
        valueToDisplay = function (obj, prop) {
            // given an object and a property, return the value to display
            if (! obj.hasOwnProperty(prop)) {
                return '(NO_SUCH_PROP)';
            } else if (obj[prop] === undefined) {
                return '(undefined)';
            } else if (obj[prop] === false) {
                return 'NO';
            } else if (obj[prop] === true) {
                return 'YES';
            } else if (obj[prop] === null) {
                return '(none)';
            } else if (obj[prop] === NaN) {
                return '(NOT_A_NUMBER)';
            }
            return obj[prop];
        },
        charsNeeded = function (arr) {
            var len, needed;
            len = arr ? arr.length : 0;
            console.log("arr has " + len + " members");
            needed = arr.reduce(function(prevVal, elem) {
                if (elem.text.length > prevVal) {
                    prevVal = elem.text.length;
                }
                return prevVal;
            }, arr[0].name.length);
            needed += 2; // ': '
            console.log("The longest entry needs " + needed + " characters total");
            return needed;
        },
        browserNavMenu = function (len, pos) {
            var r = '',
                context = {
                    forward: 0,
                    back: 0,
                    jumpToEnd: 0,
                    jumpToBegin: 0
                };
	    // context-sensitive navigation menu: selections are based on
	    // set length and cursor position:
            //   if set.length <= 1: no navigation menu at all
            //   if 1 < set.length <= 5: forward, back
            //   if set.length > 5: forward, back, jump to end/beginning
            //   if pos == 1 then back and jump to beginning are deactivated
            //   if pos == set.length then forward and jump to end are deactivated
            // here in html.js, we add  elements for each context-sensitive
            // selection. Each such element has a unique identifier, so that in
            // start.js we can check for the presence of each and handle accordingly
            if (len > 1) {
                //
                // there is at least one record to display:
                // (a) determine context
                //
                if (len > 1) {
                    context.forward = 1;
                    context.back = 1;
                }
                if (len > 5) {
                    context.jumpToEnd = 1;
                    context.jumpToBegin = 1;
                }
                if (pos === 0) {
                    context.back = 0;
                    context.jumpToBegin = 0;
                }
                if (pos === len - 1) {
                    context.forward = 0;
                    context.jumpToEnd = 0;
                }
                //
                // (b) construct navigation menu
                //
                r += 'Navigation:  ';
                if (context.back) {
                    r += '[\u2190] Previous ';
                }
                if (context.forward) {
                    r += '[\u2192] Next ';
                }
                if (context.jumpToBegin) {
                    r += '[\u2303\u2190] Jump to first ';
                }
                if (context.jumpToEnd) {
                    r += '[\u2303\u2192] Jump to last ';
                }
                r += '
';
            } else {
                r = '';
            }
            return r;
        };

    return {
        demoActionFromMenu: function () {
            return '

SAMPLE ACTION - SOMETHING IS HAPPENING

';
        },
        demoActionFromSubmenu: function () {
            return '

SAMPLE ACTION - foo bar actioning bazness

';
        },
        loginDialog: function () {
            var r = '';
            r += '<form id="loginform">';
            r += '

';
            r += cf('loginDialogChallengeText');
            r += '

';
            r += 'Username: <input name="nam" size="' + cf('loginDialogMaxLengthUsername') + '"';
            r += 'maxlength="' + cf('loginDialogMaxLengthUsername') + '" />
';
            r += 'Password: <input name="pwd" type="password" size="' + cf('loginDialogMaxLengthPassword') + '"';
            r += 'maxlength="' + cf('loginDialogMaxLengthPassword') + '" />

';
            r += '          ';
            r += '<input type="submit" value="Submit">

';
            r += '</form>';
            return r;
        },
        logout: function () {
            var r = '';
            r += '

';
            r += 'You have been logged out of our humble application

';
            r += 'Have a lot of fun!

';
            return r;
        },
        body: function () {
            var r = '';
            r += '
';

            r += '
';
            r += cf('appName');
            r += ' ';
            r += cf('appVersion');
            r += '';
            r += '
';

            r += '
';
            r += appLib.fillUserBox();
            r += '
';

            r += '
';

            r += '
';
            r += '   If application appears';
            r += '   unresponsive, make sure browser window is active and press \'TAB\'';
            r += '
';

            r += '

';

            r += '

';

            r += '
';
            // r += appLib.fillNoticesLine();
            r += '
';
            return r;
        },
        //
        // dmenu target
        //
        dmenu: function (dmn) {
            console.log("Entering html.dmenu with argument " + dmn);
            // dmn is dmenu name
            // dmo is dmenu object
            var dmo = target.pull(dmn),
                r = '',
                len = dmo.entries.length,
                i,
                back = target.pull(dmo.back),
                entry;

            r += '<form id="' + dmn + '">
' + dmo.title + '

';

            for (i = 0; i < len; i += 1) {
                // the entries are names of targets
                console.log("Attempting to pull target " + dmo.entries[i]);
                entry = target.pull(dmo.entries[i]);
                if (lib.privCheck(entry.aclProfile)) {
                    r += i + '. ' + entry.menuText + '
';
                }
            }
            r += 'X. ' + back.menuText + '
';

            r += yourChoice();

            r += '</form>';
            return r;
        },
        //
        // dform target
        //
        dform: function (dfn) {
            // dfn is dform name
            // dfo is dform object
            var dfo = target.pull(dfn);
            return function (obj) {

                console.log("Generating source code of dform " + dfn);
                var r = '<form id="' + dfo.name + '">',
                    len,
                    i,
                    allEntries,
                    needed,
                    entry;

                r += '
' + dfo.title + '

';

                if (dfo.preamble) {
                    r += dfo.preamble + '

';
                }

                // determine characters needed for padding (based on longest
                // entry)
                allEntries = lib.forceArray(dfo.entriesRead);
                allEntries = allEntries.concat(dfo.entriesWrite);
                needed = charsNeeded(allEntries);

                // READ-ONLY entries first
                len = dfo.entriesRead ? dfo.entriesRead.length : 0;
                for (i = 0; i < len; i += 1) {
                    entry = dfo.entriesRead[i];
                    if (lib.privCheck(entry.aclProfileRead)) {
                        r += lib.rightPadSpaces(entry.text.concat(':'), needed);
                        r += '';
                        r += valueToDisplay(obj, entry.prop);
                        r += '
';
                    }
                }
                r += '
';

                // READ-WRITE entries second
                len = dfo.entriesWrite ? dfo.entriesWrite.length : 0;
                for (i = 0; i < len; i += 1) {
                    entry = dfo.entriesWrite[i];
                    if (lib.privCheck(entry.aclProfileWrite)) {
                        r += lib.rightPadSpaces(entry.text.concat(':'), needed);
                        r += '<input id="' + entry.name + '" ';
                        r += 'name="entry' + i + '" ';
                        r += 'value="' + (obj[entry.prop] || '') + '" ';
                        r += 'size="' + entry.maxlen + '" ';
                        r += 'maxlength="' + entry.maxlen + '">
';
                    }
                }
                r += '
';

                // miniMenu at the bottom
                r += miniMenu(dfo.miniMenu);

                // your choice section
                r += yourChoice();

                r += '</form>';
                //console.log("Assembled source code for " + dfn + " - it has " + r.length + " characters");
                return r;
            };
        },
        dbrowser: function (dbn) {
            // dfn is dform name
            // dfo is dform object
            var dbo = target.pull(dbn);
            return function (set, pos) {

                //console.log("Generating source code of dbrowser " + dbn);
                var r = '<form id="' + dbo.name + '">',
                    len,
                    i,
                    obj,
                    entry,
                    allEntries,
                    needed;

                r += '
' + dbo.title + '

';

                if (dbo.preamble) {
                    r += dbo.preamble + '

';
                }

                // determine characters needed for padding (based on longest
                // entry)
                allEntries = lib.forceArray(dbo.entries);
                needed = charsNeeded(allEntries);

                // display entries
                len = dbo.entries ? dbo.entries.length : 0;
                obj = set[pos];
                console.log('Browsing object', obj);
                if (len > 0) {
                    for (i = 0; i < len; i += 1) {
                        entry = dbo.entries[i];
                        if (lib.privCheck(entry.aclProfile)) {
                            r += lib.rightPadSpaces(entry.text.concat(':'), needed);
                            r += '';
                            r += valueToDisplay(obj, entry.prop);
                            r += '
';
                        }
                    }
                    r += '
';
                }

		// context-sensitive navigation menu: selections are based on
		// set length and cursor position
                r += browserNavMenu(set.length, pos);

		// miniMenu at the bottom: selections are target names defined
		// in the 'miniMenu' property of the dform object
                r += miniMenu(dbo.miniMenu);

                // your choice section
                r += yourChoice();

                r += '</form>';
                console.log("Assembled source code for " + dbn + " - it has " + r.length + " characters");
                return r;
            };
        },
        //
        // dnotice target
        //
        dnotice: function (dnn) {
            console.log("Entering html.dnotice with argument " + dnn);
            // dnn is dnotice name
            // dno is dnotice object
            var dno = target.pull(dnn);
            return function () {
                var r = '';
                r += '

' + dno.title + '

';
                r += dno.preamble + '
';
                r += '

';
                r += "To leave this page, press ENTER or click the Submit button";
                r += yourChoice();
                r += '
';
                return r;
            };
        }
    };
});
<commit_msg>dbrowser: rename aclProfile -> aclProfileRead<commit_after>// *************************************************************************
// Copyright (c) 2014, SUSE LLC
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of SUSE LLC nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// *************************************************************************
//
// html.js - functions that generate HTML source code
//
"use strict";

define ([
    'cf',
    'current-user',
    'lib',
    'app/lib',
    'target'
], function (
    cf,
    currentUser,
    lib,
    appLib,
    target
) {
    var
        //
        // "Your choice" section at the bottom - shared by all target types
        //
        yourChoice = function () {
            return '
Your choice: <input name="sel" size=3 maxlength=2> ' +
                   '<input id="submitButton" type="submit" value="Submit">

'
        },
        //
        // miniMenu is shared by dform and dbrowser
        //
        miniMenu = function (mm) {
            // mm is the dbrowser miniMenu object
            var len = mm.entries.length,
                entry,
                i,
                r;
            console.log("miniMenu is ", mm);
            console.log("miniMenu length is " + len);
            if (len > 0) {
                r = 'Menu:        ';
                for (i = 0; i < len; i += 1) {
                    //console.log("i === " + i);
                    console.log("Attempting to pull target " + mm.entries[i] + " from miniMenu");
                    entry = target.pull(mm.entries[i]);
                    if (lib.privCheck(entry.aclProfile)) {
                        r += i + '. ' + entry.menuText + '  ';
                    }
                }
                r += 'X. ' + mm.back[0];
            } else {
                r = mm.back[0];
            }
            return r;
        },
        valueToDisplay = function (obj, prop) {
            // given an object and a property, return the value to display
            if (! obj.hasOwnProperty(prop)) {
                return '(NO_SUCH_PROP)';
            } else if (obj[prop] === undefined) {
                return '(undefined)';
            } else if (obj[prop] === false) {
                return 'NO';
            } else if (obj[prop] === true) {
                return 'YES';
            } else if (obj[prop] === null) {
                return '(none)';
            } else if (obj[prop] === NaN) {
                return '(NOT_A_NUMBER)';
            }
            return obj[prop];
        },
        charsNeeded = function (arr) {
            var len, needed;
            len = arr ? arr.length : 0;
            console.log("arr has " + len + " members");
            needed = arr.reduce(function(prevVal, elem) {
                if (elem.text.length > prevVal) {
                    prevVal = elem.text.length;
                }
                return prevVal;
            }, arr[0].name.length);
            needed += 2; // ': '
            console.log("The longest entry needs " + needed + " characters total");
            return needed;
        },
        browserNavMenu = function (len, pos) {
            var r = '',
                context = {
                    forward: 0,
                    back: 0,
                    jumpToEnd: 0,
                    jumpToBegin: 0
                };
	    // context-sensitive navigation menu: selections are based on
	    // set length and cursor position:
            //   if set.length <= 1: no navigation menu at all
            //   if 1 < set.length <= 5: forward, back
            //   if set.length > 5: forward, back, jump to end/beginning
            //   if pos == 1 then back and jump to beginning are deactivated
            //   if pos == set.length then forward and jump to end are deactivated
            // here in html.js, we add  elements for each context-sensitive
            // selection. Each such element has a unique identifier, so that in
            // start.js we can check for the presence of each and handle accordingly
            if (len > 1) {
                //
                // there is at least one record to display:
                // (a) determine context
                //
                if (len > 1) {
                    context.forward = 1;
                    context.back = 1;
                }
                if (len > 5) {
                    context.jumpToEnd = 1;
                    context.jumpToBegin = 1;
                }
                if (pos === 0) {
                    context.back = 0;
                    context.jumpToBegin = 0;
                }
                if (pos === len - 1) {
                    context.forward = 0;
                    context.jumpToEnd = 0;
                }
                //
                // (b) construct navigation menu
                //
                r += 'Navigation:  ';
                if (context.back) {
                    r += '[\u2190] Previous ';
                }
                if (context.forward) {
                    r += '[\u2192] Next ';
                }
                if (context.jumpToBegin) {
                    r += '[\u2303\u2190] Jump to first ';
                }
                if (context.jumpToEnd) {
                    r += '[\u2303\u2192] Jump to last ';
                }
                r += '
';
            } else {
                r = '';
            }
            return r;
        };

    return {
        demoActionFromMenu: function () {
            return '

SAMPLE ACTION - SOMETHING IS HAPPENING

';
        },
        demoActionFromSubmenu: function () {
            return '

SAMPLE ACTION - foo bar actioning bazness

';
        },
        loginDialog: function () {
            var r = '';
            r += '<form id="loginform">';
            r += '

';
            r += cf('loginDialogChallengeText');
            r += '

';
            r += 'Username: <input name="nam" size="' + cf('loginDialogMaxLengthUsername') + '"';
            r += 'maxlength="' + cf('loginDialogMaxLengthUsername') + '" />
';
            r += 'Password: <input name="pwd" type="password" size="' + cf('loginDialogMaxLengthPassword') + '"';
            r += 'maxlength="' + cf('loginDialogMaxLengthPassword') + '" />

';
            r += '          ';
            r += '<input type="submit" value="Submit">

';
            r += '</form>';
            return r;
        },
        logout: function () {
            var r = '';
            r += '

';
            r += 'You have been logged out of our humble application

';
            r += 'Have a lot of fun!

';
            return r;
        },
        body: function () {
            var r = '';
            r += '
';

            r += '
';
            r += cf('appName');
            r += ' ';
            r += cf('appVersion');
            r += '';
            r += '
';

            r += '
';
            r += appLib.fillUserBox();
            r += '
';

            r += '
';

            r += '
';
            r += '   If application appears';
            r += '   unresponsive, make sure browser window is active and press \'TAB\'';
            r += '
';

            r += '

';

            r += '

';

            r += '
';
            // r += appLib.fillNoticesLine();
            r += '
';
            return r;
        },
        //
        // dmenu target
        //
        dmenu: function (dmn) {
            console.log("Entering html.dmenu with argument " + dmn);
            // dmn is dmenu name
            // dmo is dmenu object
            var dmo = target.pull(dmn),
                r = '',
                len = dmo.entries.length,
                i,
                back = target.pull(dmo.back),
                entry;

            r += '<form id="' + dmn + '">
' + dmo.title + '

';

            for (i = 0; i < len; i += 1) {
                // the entries are names of targets
                console.log("Attempting to pull target " + dmo.entries[i]);
                entry = target.pull(dmo.entries[i]);
                if (lib.privCheck(entry.aclProfile)) {
                    r += i + '. ' + entry.menuText + '
';
                }
            }
            r += 'X. ' + back.menuText + '
';

            r += yourChoice();

            r += '</form>';
            return r;
        },
        //
        // dform target
        //
        dform: function (dfn) {
            // dfn is dform name
            // dfo is dform object
            var dfo = target.pull(dfn);
            return function (obj) {

                console.log("Generating source code of dform " + dfn);
                var r = '<form id="' + dfo.name + '">',
                    len,
                    i,
                    allEntries,
                    needed,
                    entry;

                r += '
' + dfo.title + '

';

                if (dfo.preamble) {
                    r += dfo.preamble + '

';
                }

                // determine characters needed for padding (based on longest
                // entry)
                allEntries = lib.forceArray(dfo.entriesRead);
                allEntries = allEntries.concat(dfo.entriesWrite);
                needed = charsNeeded(allEntries);

                // READ-ONLY entries first
                len = dfo.entriesRead ? dfo.entriesRead.length : 0;
                for (i = 0; i < len; i += 1) {
                    entry = dfo.entriesRead[i];
                    if (lib.privCheck(entry.aclProfileRead)) {
                        r += lib.rightPadSpaces(entry.text.concat(':'), needed);
                        r += '';
                        r += valueToDisplay(obj, entry.prop);
                        r += '
';
                    }
                }
                r += '
';

                // READ-WRITE entries second
                len = dfo.entriesWrite ? dfo.entriesWrite.length : 0;
                for (i = 0; i < len; i += 1) {
                    entry = dfo.entriesWrite[i];
                    if (lib.privCheck(entry.aclProfileWrite)) {
                        r += lib.rightPadSpaces(entry.text.concat(':'), needed);
                        r += '<input id="' + entry.name + '" ';
                        r += 'name="entry' + i + '" ';
                        r += 'value="' + (obj[entry.prop] || '') + '" ';
                        r += 'size="' + entry.maxlen + '" ';
                        r += 'maxlength="' + entry.maxlen + '">
';
                    }
                }
                r += '
';

                // miniMenu at the bottom
                r += miniMenu(dfo.miniMenu);

                // your choice section
                r += yourChoice();

                r += '</form>';
                //console.log("Assembled source code for " + dfn + " - it has " + r.length + " characters");
                return r;
            };
        },
        dbrowser: function (dbn) {
            // dfn is dform name
            // dfo is dform object
            var dbo = target.pull(dbn);
            return function (set, pos) {

                //console.log("Generating source code of dbrowser " + dbn);
                var r = '<form id="' + dbo.name + '">',
                    len,
                    i,
                    obj,
                    entry,
                    allEntries,
                    needed;

                r += '
' + dbo.title + '

';

                if (dbo.preamble) {
                    r += dbo.preamble + '

';
                }

                // determine characters needed for padding (based on longest
                // entry)
                allEntries = lib.forceArray(dbo.entries);
                needed = charsNeeded(allEntries);

                // display entries
                len = dbo.entries ? dbo.entries.length : 0;
                obj = set[pos];
                console.log('Browsing object', obj);
                if (len > 0) {
                    for (i = 0; i < len; i += 1) {
                        entry = dbo.entries[i];
                        if (lib.privCheck(entry.aclProfileRead)) {
                            r += lib.rightPadSpaces(entry.text.concat(':'), needed);
                            r += '';
                            r += valueToDisplay(obj, entry.prop);
                            r += '
';
                        }
                    }
                    r += '
';
                }

		// context-sensitive navigation menu: selections are based on
		// set length and cursor position
                r += browserNavMenu(set.length, pos);

		// miniMenu at the bottom: selections are target names defined
		// in the 'miniMenu' property of the dform object
                r += miniMenu(dbo.miniMenu);

                // your choice section
                r += yourChoice();

                r += '</form>';
                console.log("Assembled source code for " + dbn + " - it has " + r.length + " characters");
                return r;
            };
        },
        //
        // dnotice target
        //
        dnotice: function (dnn) {
            console.log("Entering html.dnotice with argument " + dnn);
            // dnn is dnotice name
            // dno is dnotice object
            var dno = target.pull(dnn);
            return function () {
                var r = '';
                r += '

' + dno.title + '

';
                r += dno.preamble + '
';
                r += '

';
                r += "To leave this page, press ENTER or click the Submit button";
                r += yourChoice();
                r += '
';
                return r;
            };
        }
    };
});
<|endoftext|>


<commit_before>/**
 * Constructor.
 *
 * @param {Object} cssjson An object literal representation of CSS folllowing CSS JSON convention (http://featureblend.com/css-json.html).
 *
 *        Example:
 *        {
 *            "selector-1": {
 *                "property-1" : "value-1",
 *                "property-n" : "value-n"
 *            }
 *        },
 *        {
 *            "selector-n": {
 *                "property-1" : "value-1",
 *                "property-n" : "value-n"
 *            }
 *        }
 *
 * @param {Function} selectorEngine
 *        A function to be used to handle the selector matching.
 *
 *        The function gets passed two arguments:
 *        {String} selector The selector.
 *        {DOMElement} context A DOM element to constrain the selector context, defaults
 *        to document if not defined in options selectorContext.
 *
 *        The function should return an Array of matching DOM element references.
 *        If no matches are found, an empty Array is expected.
 *
 * @param {Object} (Optional) options An object literal representation of options.
 *        Options:
 *        {DOMElement} selectorContext A DOM element to constrain the selector context.
 */
function CSSugar(cssjson, selectorEngine){
    var options = arguments[2] || {};
    for(var selector in cssjson){
        var elements = selectorEngine(selector, options.selectorContext||document);
        var properties = cssjson[selector]
        for(var i=0; i<elements.length; i++){
            var element = elements[i];
            for(var property in properties){
                element.style[property] = properties[property];
            }
        }
    }
}<commit_msg>Add support for custom property processor. Minor doc cleanup.<commit_after>/**
 * Constructor.
 *
 * @param {Object} cssjson An object literal representation of CSS folllowing CSS JSON convention (http://featureblend.com/css-json.html).
 *
 *        Example:
 *        {
 *            "selector-1": {
 *                "property-1" : "value-1",
 *                "property-n" : "value-n"
 *            }
 *        },
 *        {
 *            "selector-n": {
 *                "property-1" : "value-1",
 *                "property-n" : "value-n"
 *            }
 *        }
 *
 * @param {Function} selectorEngine
 *        A function to be used to handle the selector matching.
 *        The function gets passed two arguments:
 *        {String} selector The selector.
 *        {DOMElement} context A DOM element to constrain the selector context, defaults
 *        to document if not defined in options selectorContext.
 *        The function should return an Array of matching DOM element references.
 *        If no matches are found, an empty Array is expected.
 *
 * @param {Object} (Optional) options An object literal representation of options.
 *        Options:
 *        {DOMElement} selectorContext A DOM element to constrain the selector context.
 *        {Function} processor A function used to handle the processing of
 *        property/value pairs. The function gets passed one argument:
 *        {Object} An object literal having the following properties:
 *        {String} property The property name.
 *        {String} value The property value.
 *        {String} selector The governing selector.
 *        {Object} cssjson The invoked cssjson object. See constructor argument cssjson documentation.
 *        The function should return an object literal of property/values for replacement.
 *        To remove the property/value completely return and an empty object literal (eg., {})
 */
function CSSugar(cssjson, selectorEngine){
    var options = arguments[2] || {};
    for(var selector in cssjson){
    	if(cssjson.hasOwnProperty(selector)){
	        var elements = selectorEngine(selector, options.selectorContext||document);
	        var properties = cssjson[selector]
	        for(var i=0; i<elements.length; i++){
	            var element = elements[i];
	            for(var property in properties){
	            	if(properties.hasOwnProperty(property)){
	            		if(options.processor){
	            			var processorArguments = {
	            				"property": property,
	            				"value": properties[property],
	            				"selector": selector,
	            				"cssjson": cssjson
	            			};
	            			var processedProperties = options.processor(processorArguments);
	            			for(var processedProperty in processedProperties){
	            				if(processedProperties.hasOwnProperty(processedProperty)){
	            					element.style[processedProperty] = processedProperties[processedProperty];
	            				}
	            			}
	            		}else{
	            			element.style[property] = properties[property];
	            		}
	            	}
	            }
	        }
    	}
    }
}<|endoftext|>


<commit_before>/**
 * @license
 * Visual Blocks Editor
 *
 * Copyright 2012 Google Inc.
 * https://developers.google.com/blockly/
 *
 * 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.
 */

/**
 * @fileoverview Variable input field.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Blockly.FieldVariable');

goog.require('Blockly.FieldDropdown');
goog.require('Blockly.Msg');
goog.require('Blockly.Variables');
goog.require('goog.string');

/**
 * Class for a variable's dropdown field.
 * @param {?string} varname The default name for the variable.  If null,
 *     a unique variable name will be generated.
 * @param {Function=} opt_validator A function that is executed when a new
 *     option is selected.  Its sole argument is the new option value.
 * @extends {Blockly.FieldDropdown}
 * @constructor
 */
Blockly.FieldVariable = function(varname, opt_validator) {
  Blockly.FieldVariable.superClass_.constructor.call(this,
      Blockly.FieldVariable.dropdownCreate, opt_validator);
  this.setValue(varname || '');
};
goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);

/**
 * Install this dropdown on a block.
 */
Blockly.FieldVariable.prototype.init = function() {
  if (this.fieldGroup_) {
    // Dropdown has already been initialized once.
    return;
  }
  Blockly.FieldVariable.superClass_.init.call(this);
  if (!this.getValue()) {
    // Variables without names get uniquely named for this workspace.
    var workspace =
        this.sourceBlock_.isInFlyout ?
            this.sourceBlock_.workspace.targetWorkspace :
            this.sourceBlock_.workspace;
    this.setValue(Blockly.Variables.generateUniqueName(workspace));
  }
};

/**
 * Get the variable's name (use a variableDB to convert into a real name).
 * Unline a regular dropdown, variables are literal and have no neutral value.
 * @return {string} Current text.
 */
Blockly.FieldVariable.prototype.getValue = function() {
  return this.getText();
};

/**
 * Set the variable name.
 * @param {string} newValue New text.
 */
Blockly.FieldVariable.prototype.setValue = function(newValue) {
  if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
    Blockly.Events.fire(new Blockly.Events.Change(
        this.sourceBlock_, 'field', this.name, this.value_, newValue));
  }
  this.value_ = newValue;
  this.setText(newValue);
};

/**
 * Return a sorted list of variable names for variable dropdown menus.
 * Include a special option at the end for creating a new variable name.
 * @return {!Array.<string>} Array of variable names.
 * @this {!Blockly.FieldVariable}
 */
Blockly.FieldVariable.dropdownCreate = function() {
  if (this.sourceBlock_ && this.sourceBlock_.workspace) {
    // Get a copy of the list, so that adding rename and new variable options
    // doesn't modify the workspace's list.
    var variableList = this.sourceBlock_.workspace.variableList.slice(0);
  } else {
    var variableList = [];
  }
  // Ensure that the currently selected variable is an option.
  var name = this.getText();
  if (name && variableList.indexOf(name) == -1) {
    variableList.push(name);
  }
  variableList.sort(goog.string.caseInsensitiveCompare);
  variableList.push(Blockly.Msg.RENAME_VARIABLE);
  variableList.push(Blockly.Msg.DELETE_VARIABLE.replace('%1', name));
  // Variables are not language-specific, use the name as both the user-facing
  // text and the internal representation.
  var options = [];
  for (var i = 0; i < variableList.length; i++) {
    options[i] = [variableList[i], variableList[i]];
  }
  return options;
};

/**
 * Event handler for a change in variable name.
 * Special case the 'Rename variable...' and 'Delete variable...' options.
 * In the rename case, prompt the user for a new name.
 * @param {string} text The selected dropdown menu option.
 * @return {null|undefined|string} An acceptable new variable name, or null if
 *     change is to be either aborted (cancel button) or has been already
 *     handled (rename), or undefined if an existing variable was chosen.
 */
Blockly.FieldVariable.prototype.classValidator = function(text) {
  var workspace = this.sourceBlock_.workspace;
  if (text == Blockly.Msg.RENAME_VARIABLE) {
    var oldVar = this.getText();
    Blockly.hideChaff();
    text = Blockly.Variables.promptName(
        Blockly.Msg.RENAME_VARIABLE_TITLE.replace('%1', oldVar), oldVar);
    if (text) {
      Blockly.Variables.renameVariable(oldVar, text, workspace);
    }
    return null;
  } else if (text == Blockly.Msg.DELETE_VARIABLE.replace('%1',
      this.getText())) {
    Blockly.Variables.delete(this.getText(), this.sourceBlock_.workspace);
    return null;
  }
  return undefined;
};
<commit_msg>Create variables on block creation<commit_after>/**
 * @license
 * Visual Blocks Editor
 *
 * Copyright 2012 Google Inc.
 * https://developers.google.com/blockly/
 *
 * 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.
 */

/**
 * @fileoverview Variable input field.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Blockly.FieldVariable');

goog.require('Blockly.FieldDropdown');
goog.require('Blockly.Msg');
goog.require('Blockly.Variables');
goog.require('goog.string');

/**
 * Class for a variable's dropdown field.
 * @param {?string} varname The default name for the variable.  If null,
 *     a unique variable name will be generated.
 * @param {Function=} opt_validator A function that is executed when a new
 *     option is selected.  Its sole argument is the new option value.
 * @extends {Blockly.FieldDropdown}
 * @constructor
 */
Blockly.FieldVariable = function(varname, opt_validator) {
  Blockly.FieldVariable.superClass_.constructor.call(this,
      Blockly.FieldVariable.dropdownCreate, opt_validator);
  this.setValue(varname || '');
};
goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);

/**
 * Install this dropdown on a block.
 */
Blockly.FieldVariable.prototype.init = function() {
  if (this.fieldGroup_) {
    // Dropdown has already been initialized once.
    return;
  }
  Blockly.FieldVariable.superClass_.init.call(this);
  if (!this.getValue()) {
    // Variables without names get uniquely named for this workspace.
    var workspace =
        this.sourceBlock_.isInFlyout ?
            this.sourceBlock_.workspace.targetWorkspace :
            this.sourceBlock_.workspace;
    this.setValue(Blockly.Variables.generateUniqueName(workspace));
  }
  // If the selected variable doesn't exist yet, create it.
  // For instance, some blocks in the toolbox have variable dropdowns filled
  // in by default.
  if (!this.sourceBlock_.isInFlyout) {
    this.sourceBlock_.workspace.createVariable(this.getValue());
  }
};

/**
 * Get the variable's name (use a variableDB to convert into a real name).
 * Unline a regular dropdown, variables are literal and have no neutral value.
 * @return {string} Current text.
 */
Blockly.FieldVariable.prototype.getValue = function() {
  return this.getText();
};

/**
 * Set the variable name.
 * @param {string} newValue New text.
 */
Blockly.FieldVariable.prototype.setValue = function(newValue) {
  if (this.sourceBlock_ && Blockly.Events.isEnabled()) {
    Blockly.Events.fire(new Blockly.Events.Change(
        this.sourceBlock_, 'field', this.name, this.value_, newValue));
  }
  this.value_ = newValue;
  this.setText(newValue);
};

/**
 * Return a sorted list of variable names for variable dropdown menus.
 * Include a special option at the end for creating a new variable name.
 * @return {!Array.<string>} Array of variable names.
 * @this {!Blockly.FieldVariable}
 */
Blockly.FieldVariable.dropdownCreate = function() {
  if (this.sourceBlock_ && this.sourceBlock_.workspace) {
    // Get a copy of the list, so that adding rename and new variable options
    // doesn't modify the workspace's list.
    var variableList = this.sourceBlock_.workspace.variableList.slice(0);
  } else {
    var variableList = [];
  }
  // Ensure that the currently selected variable is an option.
  var name = this.getText();
  if (name && variableList.indexOf(name) == -1) {
    variableList.push(name);
  }
  variableList.sort(goog.string.caseInsensitiveCompare);
  variableList.push(Blockly.Msg.RENAME_VARIABLE);
  variableList.push(Blockly.Msg.DELETE_VARIABLE.replace('%1', name));
  // Variables are not language-specific, use the name as both the user-facing
  // text and the internal representation.
  var options = [];
  for (var i = 0; i < variableList.length; i++) {
    options[i] = [variableList[i], variableList[i]];
  }
  return options;
};

/**
 * Event handler for a change in variable name.
 * Special case the 'Rename variable...' and 'Delete variable...' options.
 * In the rename case, prompt the user for a new name.
 * @param {string} text The selected dropdown menu option.
 * @return {null|undefined|string} An acceptable new variable name, or null if
 *     change is to be either aborted (cancel button) or has been already
 *     handled (rename), or undefined if an existing variable was chosen.
 */
Blockly.FieldVariable.prototype.classValidator = function(text) {
  var workspace = this.sourceBlock_.workspace;
  if (text == Blockly.Msg.RENAME_VARIABLE) {
    var oldVar = this.getText();
    Blockly.hideChaff();
    text = Blockly.Variables.promptName(
        Blockly.Msg.RENAME_VARIABLE_TITLE.replace('%1', oldVar), oldVar);
    if (text) {
      Blockly.Variables.renameVariable(oldVar, text, workspace);
    }
    return null;
  } else if (text == Blockly.Msg.DELETE_VARIABLE.replace('%1',
      this.getText())) {
    Blockly.Variables.delete(this.getText(), this.sourceBlock_.workspace);
    return null;
  }
  return undefined;
};
<|endoftext|>


<commit_before>"use strict";

var trycatch = require('trycatch');
var qs = require('querystring');
var url = require('url');
var fs = require('fs');
var ua = require('ua-parser');
var MD = require('mobile-detect');

exports.HttpApi = function (codepath, actionmgr, valuemgr) {
	var code;

	function loadCode(appid, actionid, callback) {
		// cache mtcode in code for minimize disk usage, lazy load
		if (code === undefined) {
			fs.readFile(codepath, 'ascii', function (err, data) {
				code = data;
				replaceParam();
			});
		}
		else replaceParam();

		function replaceParam() {
			callback(code.replace('$APPID$', appid).replace('$ACTIONID$', actionid));
		}
	}

	// purpose get real ip address
	function getRemoteAddress(req) {
		return req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
	}

	// purpose: extract basic info from user agent and request parameter
	function trackBasic(request) {
		var useragent = request.headers['user-agent'];
		var r = ua.parse(useragent);
		var uri = request.params._url || "";

		var md = new MD(useragent);
		var devicetype;
		if (md.tablet() !== null)
			devicetype = 'tablet';
		else if (md.phone() !== null)
			devicetype = 'phone';
		else
			devicetype = 'desktop';

		if (uri === "" || uri.startsWith(request.headers.referer) === false) uri = request.headers.referer;
		var res = {
			_url: uri,
			_ref: request.params._ref,
			_typeid: request.params._typeid,
			_ip: getRemoteAddress(request),
			_deltat: request.params._deltat,
			_os: r.os.family,
			_browser: r.ua.family,
			_browserver: r.ua.major + '.' + r.ua.minor,
			_osver: r.os.major + '.' + r.os.minor,
			_deviceid: r.device.family,
			_scr: request.params._scr,
			_lang: request.headers["accept-language"],
			_devicetype: devicetype
		};
		for (var i in request.params) if (request.params.hasOwnProperty(i))
			if (i.startsWith('_') === false)
				res[i] = request.params[i];

		// extract campaign
		var query = url.parse(uri, true).query;
		res._utm_source = query.utm_source;
		res._utm_campaign = query.utm_campaign;
		res._utm_term = query.utm_term;
		res._utm_content = query.utm_content;
		res._utm_medium = query.utm_medium;

		return res;
	}

	function getMtid(req, appid, res, callback) {
		var mtid = getCookie(req, "mtid");
		if (mtid === undefined) {
			return actionmgr.setupRaw(appid, function (mtid) {
				setCookie(res, "mtid", mtid, '/' + appid);
				callback(mtid);
			});
		}

		// check if mtid is valid
		actionmgr.ismtidValid(appid, mtid, function (ret) {
			if (ret) callback(mtid);
			else {
				eraseCookie(res, "mtid", '/' + appid);
				actionmgr.setupRaw(appid, function (mtid) {
					setCookie(res, "mtid", mtid, '/' + appid);
					callback(mtid);
				});
			}
		});
	}

	function eraseCookie(res, name, path) {
		res.setHeader('Set-Cookie', name + "=x; expires=Wed, 21 Aug 1995 11:11:11 GMT; path=/" + path);
	}

	function clear(req, res) {
		// delete the cookie
		eraseCookie(res, 'mtid', '/' + req.appid);
		res.end();
	}

	function track(req, res) {
		var appid = req.appid;
		var data = trackBasic(req);
		getMtid(req, appid, res, function (mtid) {
			data._mtid = mtid;
			actionmgr.saveRaw(appid, data, function (actionid) {
				res.setHeader('Content-Type', 'text/plain');
				res.end("//" + actionid);
			});
		});
	}

	function info(req, res) {
		var appid = req.appid;
		getMtid(req, appid, res, function (mtid) {
			var data = {};
			for (var i in req.params) if (req.params.hasOwnProperty(i)) {
				if (i.startsWith('_') === false) data[i] = req.params[i];
			}

			actionmgr.identifyRaw(appid, {mtid: mtid, user: data}, function (mtid) {
				//set new mtid if need
				setCookie(res, "mtid", mtid, 'api/' + appid);
				res.setHeader('Content-Type', 'text/plain');

				res.end("//" + mtid);
			});
		});
	}

	function x(req, res) {
		actionmgr.x(req, res, function () {
		});
	}

	function getCookie(req, name) {
		var list = {}, rc = req.headers.cookie;
		rc && rc.split(';').forEach(function (cookie) {
			var parts = cookie.split('=');
			list[parts.shift().trim()] = decodeURIComponent(parts.join('='));
		});
		return list[name];
	}

	function setCookie(res, name, value, path) {
		var tenyearlater = new Date().getYear() + 10 + 1900;
		res.setHeader('Set-Cookie', name + '=' + encodeURIComponent(value) + "; expires=Wed, 21 Aug " + tenyearlater + " 11:11:11 GMT; path=/" + path);
	}

	function fix(req, res) {
		var appid = req.appid;
		var actionid = req.actionid;
		var lastactionid = req.lastactionid;
		var data = trackBasic(req);
		getMtid(req, appid, res, function (mtid) {
			data._mtid = mtid;
			actionmgr.fixRaw(appid, actionid, lastactionid, data, function () {
				res.end();
			});
		});
	}

	function suggest(req, res) {
		valuemgr.suggest(req.appid + "", req.typeid + "", req.field + "", req.qr + "", function (results) {
			res.setHeader('Content-Type', 'application/json');
			res.end(JSON.stringify(results));
		});
	}

	function pageview(req, res) {
		var appid = req.appid;
		// record an new pageview
		var data = trackBasic(req);
		getMtid(req, appid, res, function (mtid) {
			data._mtid = mtid;
			data._typeid = 'pageview';

			actionmgr.saveRaw(appid, data, function (actionid) {
				// return code
				loadCode(appid, actionid, function (code) {
					res.end(code);
				});
			});
		});
	}

	this.route = function (req, res) {
		var me = this;
		trycatch(function () {
			var url_parts = url.parse(req.url, true);
			if (req.method === 'POST') {
				var body = '';
				req.on('data', function (data) {
					body += data;
				});
				req.on('end', function () {
					req['params'] = qs.parse(body);
					handle(req, res, url_parts.pathname);
				});
			}
			else if (req.method === 'GET') {
				req['params'] = url_parts.query;
				handle(req, res, url_parts.pathname);
			}

			function handle(req, res, path) {
				var parts = path.split('/');
				res.statusCode = 200;
				req['appid'] = parts[1];
				var action = parts[2];
				if (action === 'track') track(req, res);
				else if (action === '' || action === undefined) pageview(req, res);
				else if (action === 'clear') clear(req, res);
				else if (action === 'info') info(req, res);
				else if (action === 'x') {
					req['actionid'] = parts[3];
					x(req, res);
				}
				else if (action === 'suggest') {
					req['typeid'] = parts[3];
					req['field'] = parts[4];
					req['qr'] = parts[5];
					suggest(req, res);
				}
				else if (action === 'fix') {
					var query = url.parse(path, true).query;
					req['actionid'] = req.params.actionid;
					req['lastactionid'] = req.params.lastactionid;
					fix(req, res);
				} else {
					res.statusCode = 404;
					res.end('action "' + action + '" not found, action must be one of [code, clear, ingo, fix, track]');
				}
			}
		}, function (err) {
			res.statusCode = 500;
			res.end();
			console.log(err, err.stack);
		});
	};
};<commit_msg>fix wrong cookie path<commit_after>"use strict";

var trycatch = require('trycatch');
var qs = require('querystring');
var url = require('url');
var fs = require('fs');
var ua = require('ua-parser');
var MD = require('mobile-detect');

exports.HttpApi = function (codepath, actionmgr, valuemgr) {
	var code;

	function loadCode(appid, actionid, callback) {
		// cache mtcode in code for minimize disk usage, lazy load
		if (code === undefined) {
			fs.readFile(codepath, 'ascii', function (err, data) {
				code = data;
				replaceParam();
			});
		}
		else replaceParam();

		function replaceParam() {
			callback(code.replace('$APPID$', appid).replace('$ACTIONID$', actionid));
		}
	}

	// purpose get real ip address
	function getRemoteAddress(req) {
		return req.headers['x-forwarded-for'] || req.connection.remoteAddress || req.socket.remoteAddress || req.connection.socket.remoteAddress;
	}

	// purpose: extract basic info from user agent and request parameter
	function trackBasic(request) {
		var useragent = request.headers['user-agent'];
		var r = ua.parse(useragent);
		var uri = request.params._url || "";

		var md = new MD(useragent);
		var devicetype;
		if (md.tablet() !== null)
			devicetype = 'tablet';
		else if (md.phone() !== null)
			devicetype = 'phone';
		else
			devicetype = 'desktop';

		if (uri === "" || uri.startsWith(request.headers.referer) === false) uri = request.headers.referer;
		var res = {
			_url: uri,
			_ref: request.params._ref,
			_typeid: request.params._typeid,
			_ip: getRemoteAddress(request),
			_deltat: request.params._deltat,
			_os: r.os.family,
			_browser: r.ua.family,
			_browserver: r.ua.major + '.' + r.ua.minor,
			_osver: r.os.major + '.' + r.os.minor,
			_deviceid: r.device.family,
			_scr: request.params._scr,
			_lang: request.headers["accept-language"],
			_devicetype: devicetype
		};
		for (var i in request.params) if (request.params.hasOwnProperty(i))
			if (i.startsWith('_') === false)
				res[i] = request.params[i];

		// extract campaign
		var query = url.parse(uri, true).query;
		res._utm_source = query.utm_source;
		res._utm_campaign = query.utm_campaign;
		res._utm_term = query.utm_term;
		res._utm_content = query.utm_content;
		res._utm_medium = query.utm_medium;

		return res;
	}

	function getMtid(req, appid, res, callback) {
		var mtid = getCookie(req, "mtid");
		if (mtid === undefined) {
			return actionmgr.setupRaw(appid, function (mtid) {
				setCookie(res, "mtid", mtid, appid);
				callback(mtid);
			});
		}

		// check if mtid is valid
		actionmgr.ismtidValid(appid, mtid, function (ret) {
			if (ret) callback(mtid);
			else {
				eraseCookie(res, "mtid",  appid);
				actionmgr.setupRaw(appid, function (mtid) {
					setCookie(res, "mtid", mtid,  appid);
					callback(mtid);
				});
			}
		});
	}

	function eraseCookie(res, name, path) {
		res.setHeader('Set-Cookie', name + "=x; expires=Wed, 21 Aug 1995 11:11:11 GMT; path=/" + path);
	}

	function clear(req, res) {
		// delete the cookie
		eraseCookie(res, 'mtid',  req.appid);
		res.end();
	}

	function track(req, res) {
		var appid = req.appid;
		var data = trackBasic(req);
		getMtid(req, appid, res, function (mtid) {
			data._mtid = mtid;
			actionmgr.saveRaw(appid, data, function (actionid) {
				res.setHeader('Content-Type', 'text/plain');
				res.end("//" + actionid);
			});
		});
	}

	function info(req, res) {
		var appid = req.appid;
		getMtid(req, appid, res, function (mtid) {
			var data = {};
			for (var i in req.params) if (req.params.hasOwnProperty(i)) {
				if (i.startsWith('_') === false) data[i] = req.params[i];
			}

			actionmgr.identifyRaw(appid, {mtid: mtid, user: data}, function (mtid) {
				//set new mtid if need
				setCookie(res, "mtid", mtid,  appid);
				res.setHeader('Content-Type', 'text/plain');

				res.end("//" + mtid);
			});
		});
	}

	function x(req, res) {
		actionmgr.x(req, res, function () {
		});
	}

	function getCookie(req, name) {
		var list = {}, rc = req.headers.cookie;
		rc && rc.split(';').forEach(function (cookie) {
			var parts = cookie.split('=');
			list[parts.shift().trim()] = decodeURIComponent(parts.join('='));
		});
		return list[name];
	}

	function setCookie(res, name, value, path) {
		var tenyearlater = new Date().getYear() + 10 + 1900;
		res.setHeader('Set-Cookie', name + '=' + encodeURIComponent(value) + "; expires=Wed, 21 Aug " + tenyearlater + " 11:11:11 GMT; path=/" + path);
	}

	function fix(req, res) {
		var appid = req.appid;
		var actionid = req.actionid;
		var lastactionid = req.lastactionid;
		var data = trackBasic(req);
		getMtid(req, appid, res, function (mtid) {
			data._mtid = mtid;
			actionmgr.fixRaw(appid, actionid, lastactionid, data, function () {
				res.end();
			});
		});
	}

	function suggest(req, res) {
		valuemgr.suggest(req.appid + "", req.typeid + "", req.field + "", req.qr + "", function (results) {
			res.setHeader('Content-Type', 'application/json');
			res.end(JSON.stringify(results));
		});
	}

	function pageview(req, res) {
		var appid = req.appid;
		// record an new pageview
		var data = trackBasic(req);
		getMtid(req, appid, res, function (mtid) {
			data._mtid = mtid;
			data._typeid = 'pageview';

			actionmgr.saveRaw(appid, data, function (actionid) {
				// return code
				loadCode(appid, actionid, function (code) {
					res.end(code);
				});
			});
		});
	}

	this.route = function (req, res) {
		var me = this;
		trycatch(function () {
			var url_parts = url.parse(req.url, true);
			if (req.method === 'POST') {
				var body = '';
				req.on('data', function (data) {
					body += data;
				});
				req.on('end', function () {
					req['params'] = qs.parse(body);
					handle(req, res, url_parts.pathname);
				});
			}
			else if (req.method === 'GET') {
				req['params'] = url_parts.query;
				handle(req, res, url_parts.pathname);
			}

			function handle(req, res, path) {
				var parts = path.split('/');
				res.statusCode = 200;
				req['appid'] = parts[1];
				var action = parts[2];
				if (action === 'track') track(req, res);
				else if (action === '' || action === undefined) pageview(req, res);
				else if (action === 'clear') clear(req, res);
				else if (action === 'info') info(req, res);
				else if (action === 'x') {
					req['actionid'] = parts[3];
					x(req, res);
				}
				else if (action === 'suggest') {
					req['typeid'] = parts[3];
					req['field'] = parts[4];
					req['qr'] = parts[5];
					suggest(req, res);
				}
				else if (action === 'fix') {
					var query = url.parse(path, true).query;
					req['actionid'] = req.params.actionid;
					req['lastactionid'] = req.params.lastactionid;
					fix(req, res);
				} else {
					res.statusCode = 404;
					res.end('action "' + action + '" not found, action must be one of [code, clear, ingo, fix, track]');
				}
			}
		}, function (err) {
			res.statusCode = 500;
			res.end();
			console.log(err, err.stack);
		});
	};
};<|endoftext|>


<commit_before>exports.PropMgr = function (db, mongodb, async, converter, prefix, mtthrow) {
	var me = this;
	var props = [{
			name: "Age", code: "age",
			operators: [
				{name: "Greater than", code: "gt"},
				{name: "Greater or equal", code: "gte"},
				{name: "Equal", code: "eq"},
				{name: "Less or equal", code: "lte"},
				{name: "Less than", code: "lt"},
			]
		}, {
			name: "Gender", code: "gender",
			operators: [{name: "Equal", code: "eq"}]
		},
		//{
		//	name: "Phone", code: "phone",
		//	operators: [{ name: "Equal", code: "eq" }]
		//}, {
		//	name: "Email", code: "email",
		//	operators: [{ name: "Equal", code: "eq" },
		//	{name: "Contain", code: "con"},
		//		{name: "Start with", code: "sw"},
		//		{name: "End with", code: "ew"},
		//		{name: "Not contain", code: "ncon"}]
		//},
		{
			name: "Number of Purchase",
			code: '_numberPurchase',
			operators: [{name: "Equal", code: "eq"}]
		},
		 {
			name: "Country", code: "_country",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		}, {
			name: "City", code: "_city",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},
		// {
		// 	name: "Time zone", code: "_timezone",
		// 	operators: [{name: "Equal", code: "eq"}]
		// },
		{
			name: "Device Type", code: "_devicetype",
			operators: [{name: "Equal", code: "eq"}]
		}, {
			name: "Device", code: "_deviceid",
			operators:  [{name: "Equal", code: "eq"},
                                {name: "Contain", code: "con"},
                                {name: "Start with", code: "sw"},
                                {name: "End with", code: "ew"},
                                {name: "Not contain", code: "ncon"}]
		 }, {
			name: "Operating System", code: "_os",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		}, {
			name: "Browser", code: "_browser",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		}, {
			name: "Language", code: "_lang",
			operators: [
				{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}
			]
		}, {
			name: "Screen Resolution", code: "_scr",
			operators: [
				{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}
			]
		}, {
			name: "Channel", code: "_reftype",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},{
			name: "Referrer", code: "_ref",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},
		// {
		// 	name: "Location", code: "_location",
		// 	operators: [{name: "Equal", code: "eq"},
		// 		{name: "Contain", code: "con"},
		// 		{name: "Start with", code: "sw"},
		// 		{name: "End with", code: "ew"},
		// 		{name: "Not contain", code: "ncon"}]
		// },
		{
			name: "OS Version", code: "_osver",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},{
			name: "Browser Version", code: "_browserver",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},

		/* {
			name: "Campaign", code: "_campaign",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},*/{
			name: "Last-touch Campaign", code: "_lastcampaign",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},{
			name: "First-touch Campaign", code: "_firstcampaign",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		}, {
			name: "Revenue", code: "_revenue",
			operators: [
				{name: "Greater than", code: "gt"},
				{name: "Greater or equal", code: "gte"},
				{name: "Equal", code: "eq"},
				{name: "Less or equal", code: "lte"},
				{name: "Less than", code: "lt"},
			]
		}
		// , {
		// 	name: "Did Purchase", code: "purchase",
		// 	operators: [{name: "Count", code: "count"}]
		// }

	];

	this.list = function (req, res) {

		res.json(props);
	};
};
<commit_msg>update campaign<commit_after>exports.PropMgr = function (db, mongodb, async, converter, prefix, mtthrow) {
	var me = this;
	var props = [
		{
			name: "Campaign", code: "_campaign",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},
		{
			name: "Campaign Source", code: "_utm_source",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},
		{
			name: "Campaign Medium", code: "_utm_medium",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},
		{
			name: "Campaign Term", code: "_utm_term",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},
		{
			name: "Campaign Content", code: "_utm_content",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},
		{
			name: "Last-touch Campaign", code: "_lastcampaign",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},{
			name: "First-touch Campaign", code: "_firstcampaign",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},
		{
			name: "Age", code: "age",
			operators: [
				{name: "Greater than", code: "gt"},
				{name: "Greater or equal", code: "gte"},
				{name: "Equal", code: "eq"},
				{name: "Less or equal", code: "lte"},
				{name: "Less than", code: "lt"},
			]
		}, {
			name: "Gender", code: "gender",
			operators: [{name: "Equal", code: "eq"}]
		},
		//{
		//	name: "Phone", code: "phone",
		//	operators: [{ name: "Equal", code: "eq" }]
		//}, {
		//	name: "Email", code: "email",
		//	operators: [{ name: "Equal", code: "eq" },
		//	{name: "Contain", code: "con"},
		//		{name: "Start with", code: "sw"},
		//		{name: "End with", code: "ew"},
		//		{name: "Not contain", code: "ncon"}]
		//},
		{
			name: "Number of Purchase",
			code: '_numberPurchase',
			operators: [{name: "Equal", code: "eq"}]
		},
		 {
			name: "Country", code: "_country",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		}, {
			name: "City", code: "_city",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},
		// {
		// 	name: "Time zone", code: "_timezone",
		// 	operators: [{name: "Equal", code: "eq"}]
		// },
		{
			name: "Device Type", code: "_devicetype",
			operators: [{name: "Equal", code: "eq"}]
		}, {
			name: "Device", code: "_deviceid",
			operators:  [{name: "Equal", code: "eq"},
                                {name: "Contain", code: "con"},
                                {name: "Start with", code: "sw"},
                                {name: "End with", code: "ew"},
                                {name: "Not contain", code: "ncon"}]
		 }, {
			name: "Operating System", code: "_os",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		}, {
			name: "Browser", code: "_browser",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		}, {
			name: "Language", code: "_lang",
			operators: [
				{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}
			]
		}, {
			name: "Screen Resolution", code: "_scr",
			operators: [
				{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}
			]
		}, {
			name: "Channel", code: "_reftype",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},{
			name: "Referrer", code: "_ref",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},
		// {
		// 	name: "Location", code: "_location",
		// 	operators: [{name: "Equal", code: "eq"},
		// 		{name: "Contain", code: "con"},
		// 		{name: "Start with", code: "sw"},
		// 		{name: "End with", code: "ew"},
		// 		{name: "Not contain", code: "ncon"}]
		// },
		{
			name: "OS Version", code: "_osver",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		},{
			name: "Browser Version", code: "_browserver",
			operators: [{name: "Equal", code: "eq"},
				{name: "Contain", code: "con"},
				{name: "Start with", code: "sw"},
				{name: "End with", code: "ew"},
				{name: "Not contain", code: "ncon"}]
		}, {
			name: "Revenue", code: "_revenue",
			operators: [
				{name: "Greater than", code: "gt"},
				{name: "Greater or equal", code: "gte"},
				{name: "Equal", code: "eq"},
				{name: "Less or equal", code: "lte"},
				{name: "Less than", code: "lt"},
			]
		}
		// , {
		// 	name: "Did Purchase", code: "purchase",
		// 	operators: [{name: "Count", code: "count"}]
		// }

	];

	this.list = function (req, res) {

		res.json(props);
	};
};
<|endoftext|>


<commit_before>// Curious client-side JSON parsing
//

var CuriousObjects = (function() {
  function CuriousObject(hash_data, url) {
    this.id = hash_data.id;
    for (var k in hash_data) {
      this[k] = hash_data[k];
    }
    this.__url = url;
  }

  function parse_objects(data) {
    if (data.objects === undefined) { return []; }
    var objects = [];
    for (var i=0; i<data.objects.length; i++) {
      var obj = data.objects[i];
      var url = data.urls[i];
      var obj_data = {};
      for (var j=0; j<data.fields.length; j++) {
        obj_data[data.fields[j]] = obj[j];
      }
      objects.push(new CuriousObject(obj_data, url));
    }
    return objects;
  }

  function parse_results(relationships, results, existing_object_dicts) {
    // get objects associated with each subquery. for each subquery, build a
    // hash of ID to object. existing_object_dicts should be an array of dicts,
    // each dict is a mapping of ID to existing objects. if existing objects
    // are specified, will build relationships using existing objects.

    var objects = [];

    for (var i=0; i<results.data.length; i++) {
      var result_objects = parse_objects(results.data[i]);
      var d = {};
      for (var j=0; j<result_objects.length; j++) {
        if (existing_object_dicts !== undefined && existing_object_dicts !== null &&
            existing_object_dicts[i] !== undefined && existing_object_dicts[i] !== null &&
            existing_object_dicts[i][result_objects[j].id] !== undefined) {
          d[result_objects[j].id] = existing_object_dicts[i][result_objects[j].id];
        }
        else {
          d[result_objects[j].id] = result_objects[j];
        }
      }
      objects.push(d);
    }

    // for each subquery, add a relationship to results of next subquery, and
    // then a reverse relationship
    for (var i=1; i<results.results.length; i++) {
      var rel = relationships[i];

      var res_tups = results.results[i].objects;
      var join_idx = results.results[i].join_index;
      var join_src = objects[join_idx];
      var join_obj = objects[i];
      var rev = relationships[join_idx];

      // add empty replationship
      for (var k in join_src) { join_src[k][rel] = []; }
      for (var k in join_obj) { join_obj[k][rev] = []; }

      for (var j=0; j<res_tups.length; j++) {
        var obj_src = res_tups[j];
        var src = join_src[obj_src[1]];
        if (obj_src[0]) {
          var obj = join_obj[obj_src[0]];

          // forward relationship from query to next query
          src[rel].push(obj);
          // reverse relationship
          obj[rev].push(src);
        }
      }
    }

    return objects;
  }

  function dict_to_array(d) {
    var r = [];
    for (var k in d) { r.push(d[k]); }
    return r;
  }

  function array_to_dict(a) {
    var d = {};
    for (var i=0; i<a.length; i++) {
      d[a[i].id] = a[i];
    }
    return d;
  }

  function id_list(objects) {
    var ids = [];
    for (var i=0; i<objects.length; i++) { ids.push(objects[i].id); }
    if (ids.length === 0) { return null; }
    return _.uniq(ids).join(',');
  }

  return {
    parse: parse_results,
    d2a: dict_to_array,
    a2d: array_to_dict,
    id_list: id_list
  }

}());

// Helper for making a Curious query and getting back parsed objects. Use with
// angular $http compatible HTTP request facilities (e.g. jQuery?)

var CuriousQ = function(curious_url, http) {
  function __get(q, params, relationships, existing_object_arrays, cb) {
    console.log(q);

    var existing_object_dicts = undefined;
    if (existing_object_arrays) {
      existing_object_dicts = _.map(existing_object_arrays, function(data_array) {
        return CuriousObjects.a2d(data_array);
      });
    }

    var args = {d: 1, x: 1, fk: 0, q: q};
    if (params) {
      for (var k in params) { if (args[k] === undefined) { args[k] = params[k]; } }
    }

    http.post(curious_url, args).success(function(resp) {
      var objects = CuriousObjects.parse(relationships, resp.result, existing_object_dicts);
      for (var i=0; i<objects.length; i++) { objects[i] = CuriousObjects.d2a(objects[i]); }
      // console.log(objects);
      cb(objects);
    });
  }

  function get(q, relationships, cb) { __get(q, null, relationships, null, cb); }
  function get_with_objs(q, relationships, existing_object_arrays, cb) {
    __get(q, null, relationships, existing_object_arrays, cb);
  }
  function get_with_start(q, relationships, starting_objects, cb) {
    var existing_object_arrays = [];
    _.map(relationships, function(x) { existing_object_arrays.push(null); })
    existing_object_arrays[0] = starting_objects;
    __get(q, null, relationships, existing_object_arrays, cb);
  }

  return {
    get: get,
    get_with_objs: get_with_objs,
    get_with_start: get_with_start
  }
};
<commit_msg>Separate id list and id string methods<commit_after>// Curious client-side JSON parsing
//

var CuriousObjects = (function() {
  function CuriousObject(hash_data, url) {
    this.id = hash_data.id;
    for (var k in hash_data) {
      this[k] = hash_data[k];
    }
    this.__url = url;
  }

  function parse_objects(data) {
    if (data.objects === undefined) { return []; }
    var objects = [];
    for (var i=0; i<data.objects.length; i++) {
      var obj = data.objects[i];
      var url = data.urls[i];
      var obj_data = {};
      for (var j=0; j<data.fields.length; j++) {
        obj_data[data.fields[j]] = obj[j];
      }
      objects.push(new CuriousObject(obj_data, url));
    }
    return objects;
  }

  function parse_results(relationships, results, existing_object_dicts) {
    // get objects associated with each subquery. for each subquery, build a
    // hash of ID to object. existing_object_dicts should be an array of dicts,
    // each dict is a mapping of ID to existing objects. if existing objects
    // are specified, will build relationships using existing objects.

    var objects = [];

    for (var i=0; i<results.data.length; i++) {
      var result_objects = parse_objects(results.data[i]);
      var d = {};
      for (var j=0; j<result_objects.length; j++) {
        if (existing_object_dicts !== undefined && existing_object_dicts !== null &&
            existing_object_dicts[i] !== undefined && existing_object_dicts[i] !== null &&
            existing_object_dicts[i][result_objects[j].id] !== undefined) {
          d[result_objects[j].id] = existing_object_dicts[i][result_objects[j].id];
        }
        else {
          d[result_objects[j].id] = result_objects[j];
        }
      }
      objects.push(d);
    }

    // for each subquery, add a relationship to results of next subquery, and
    // then a reverse relationship
    for (var i=1; i<results.results.length; i++) {
      var rel = relationships[i];

      var res_tups = results.results[i].objects;
      var join_idx = results.results[i].join_index;
      var join_src = objects[join_idx];
      var join_obj = objects[i];
      var rev = relationships[join_idx];

      // add empty replationship
      for (var k in join_src) { join_src[k][rel] = []; }
      for (var k in join_obj) { join_obj[k][rev] = []; }

      for (var j=0; j<res_tups.length; j++) {
        var obj_src = res_tups[j];
        var src = join_src[obj_src[1]];
        if (obj_src[0]) {
          var obj = join_obj[obj_src[0]];

          // forward relationship from query to next query
          src[rel].push(obj);
          // reverse relationship
          obj[rev].push(src);
        }
      }
    }

    return objects;
  }

  function dict_to_array(d) {
    var r = [];
    for (var k in d) { r.push(d[k]); }
    return r;
  }

  function array_to_dict(a) {
    var d = {};
    for (var i=0; i<a.length; i++) {
      d[a[i].id] = a[i];
    }
    return d;
  }

  function id_list(objects) {
    var ids = [];
    for (var i=0; i<objects.length; i++) { ids.push(objects[i].id); }
    return _.uniq(ids);
  }

  function id_str(objects) {
    var ids = id_list(objects);
    if (ids.length === 0) { return null; }
    return ids.join(',');
  }

  return {
    parse: parse_results,
    d2a: dict_to_array,
    a2d: array_to_dict,
    id_list: id_list,
    id_str: id_str
  }

}());

// Helper for making a Curious query and getting back parsed objects. Use with
// angular $http compatible HTTP request facilities (e.g. jQuery?)

var CuriousQ = function(curious_url, http) {
  function __get(q, params, relationships, existing_object_arrays, cb) {
    console.log(q);

    var existing_object_dicts = undefined;
    if (existing_object_arrays) {
      existing_object_dicts = _.map(existing_object_arrays, function(data_array) {
        if (data_array) { return CuriousObjects.a2d(data_array); }
        else { return null; }
      });
    }

    var args = {d: 1, x: 1, fk: 0, q: q};
    if (params) {
      for (var k in params) { if (args[k] === undefined) { args[k] = params[k]; } }
    }

    http.post(curious_url, args).success(function(resp) {
      var objects = CuriousObjects.parse(relationships, resp.result, existing_object_dicts);
      for (var i=0; i<objects.length; i++) { objects[i] = CuriousObjects.d2a(objects[i]); }
      // console.log(objects);
      cb(objects);
    });
  }

  function get(q, relationships, cb) { __get(q, null, relationships, null, cb); }
  function get_with_objs(q, relationships, existing_object_arrays, cb) {
    __get(q, null, relationships, existing_object_arrays, cb);
  }
  function get_with_start(q, relationships, starting_objects, cb) {
    var existing_object_arrays = [];
    _.map(relationships, function(x) { existing_object_arrays.push(null); })
    existing_object_arrays[0] = starting_objects;
    __get(q, null, relationships, existing_object_arrays, cb);
  }

  return {
    get: get,
    get_with_objs: get_with_objs,
    get_with_start: get_with_start
  }
};
<|endoftext|>


<commit_before>function (newDoc, oldDoc, userCtx) {
  function forbidden(message) {
    throw {forbidden : message};
  };

  function unauthorized(message) {
    throw {unauthorized : message};
  };

  if (userCtx.roles.indexOf('_admin') == -1) {
    // admin can edit anything, only check when not admin...
    if (newDoc._deleted) {
      forbidden("You may not delete a doc.");
    }

    if (oldDoc.profile && oldDoc.profile.name) {
      if (oldDoc.profile.name != userCtx.name) {
        forbidden("You may not edit someone else's document.");
      }
    }
  }
}
<commit_msg>Bugfix: allow anyone create a document<commit_after>function (newDoc, oldDoc, userCtx) {
  function forbidden(message) {
    throw {forbidden : message};
  };

  function unauthorized(message) {
    throw {unauthorized : message};
  };

  if (userCtx.roles.indexOf('_admin') == -1) {
    // admin can edit anything, only check when not admin...
    if (newDoc._deleted) {
      forbidden("You may not delete a doc.");
    }

    if (oldDoc == null) {
      return;
    }

    if (oldDoc.profile && oldDoc.profile.name) {
      if (oldDoc.profile.name != userCtx.name) {
        forbidden("You may not edit someone else's document.");
      }
    }
  }
}
<|endoftext|>


<commit_before>var Template = require('../template')
    , novaform = require('novaform');

function EBApp(options) {
    if (!(this instanceof EBApp)) {
        return new EBApp(options);
    }

    Template.call(this);

    var name = options.name;
    var optionSettings = options.optionSettings;
    var artifact = options.artifact;

    var cname = name.charAt(0).toUpperCase() + name.slice(1);
    function makeName(str) {
        return cname + str;
    }

    var app = novaform.eb.Application(makeName('App'), {
        ApplicationName: name,
        Description: name + ' application',
    });

    var configTemplate = novaform.eb.ConfigurationTemplate(makeName('ConfigTemplate'), {
        ApplicationName: app,
        Description: name + ' configution template',
        SolutionStackName: '64bit Amazon Linux 2015.03 v1.4.4 running Node.js',
        OptionSettings: optionSettings,
    });

    var version = novaform.eb.ApplicationVersion(makeName('Version'), {
        Description: artifact.timestamp,
        ApplicationName: app,
        SourceBundle: {
            S3Bucket: artifact.bucket,
            S3Key: artifact.key,
        },
    });

    var environment = novaform.eb.Environment(makeName('Environment'), {
        Description: name + ' environment',
        ApplicationName: name,
        TemplateName: configTemplate,
        VersionLabel: version,
    });

    this.app = this._addResource(app);
    this.configTemplate = this._addResource(configTemplate);
    this.version = this._addResource(version);
    this.environment = this._addResource(environment);
}
EBApp.prototype = Object.create(Template.prototype);

module.exports = EBApp;
<commit_msg>update node stack for eb template<commit_after>var Template = require('../template')
    , novaform = require('novaform');

function EBApp(options) {
    if (!(this instanceof EBApp)) {
        return new EBApp(options);
    }

    Template.call(this);

    var name = options.name;
    var optionSettings = options.optionSettings;
    var artifact = options.artifact;

    var cname = name.charAt(0).toUpperCase() + name.slice(1);
    function makeName(str) {
        return cname + str;
    }

    var app = novaform.eb.Application(makeName('App'), {
        ApplicationName: name,
        Description: name + ' application',
    });

    var configTemplate = novaform.eb.ConfigurationTemplate(makeName('ConfigTemplate'), {
        ApplicationName: app,
        Description: name + ' configution template',
        SolutionStackName: '64bit Amazon Linux 2015.03 v2.0.0 running Node.js',
        OptionSettings: optionSettings,
    });

    var version = novaform.eb.ApplicationVersion(makeName('Version'), {
        Description: artifact.timestamp,
        ApplicationName: app,
        SourceBundle: {
            S3Bucket: artifact.bucket,
            S3Key: artifact.key,
        },
    });

    var environment = novaform.eb.Environment(makeName('Environment'), {
        Description: name + ' environment',
        ApplicationName: name,
        TemplateName: configTemplate,
        VersionLabel: version,
    });

    this.app = this._addResource(app);
    this.configTemplate = this._addResource(configTemplate);
    this.version = this._addResource(version);
    this.environment = this._addResource(environment);
}
EBApp.prototype = Object.create(Template.prototype);

module.exports = EBApp;
<|endoftext|>