<commit_before>/*global define,dojo,console */
/*jslint browser:true,sloppy:true,nomen:true,unparam:true,plusplus:true */
/*
 | Copyright 2014 Esri
 |
 | 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.
 */
//============================================================================================================================//
define([
    "dojo/_base/declare",
    "dojo/_base/array",
    "dojo/_base/lang",
    "dojo/Deferred",
    "dojo/json",
    "dojo/on",
    "dojo/topic",
    "esri/dijit/PopupTemplate",
    "esri/graphic",
    "esri/InfoTemplate",
    "esri/layers/FeatureLayer",
    "esri/tasks/query",
    "esri/tasks/QueryTask",
    "esri/tasks/RelationshipQuery",
    "dojo/domReady!"
], function (
    declare,
    array,
    lang,
    Deferred,
    JSON,
    on,
    topic,
    PopupTemplate,
    Graphic,
    InfoTemplate,
    FeatureLayer,
    Query,
    QueryTask,
    RelationshipQuery
) {

    //========================================================================================================================//

    return declare([], {
        appConfig: null,

        /**
         * Encapsulates the management of a layer and its related table.
         * @param {object} config Application configuration
         * @constructor
         */
        constructor: function (config) {
            this.appConfig = config;
        },

        /**
         * Returns the fields of the feature layer holding the items.
         * @return {array} List of fields
         */
        getItemFields: function () {
            return this._itemFields;
        },

        /**
         * Returns the fields of the table holding the comments.
         * @return {array} List of fields
         */
        getCommentFields: function () {
            return this._commentFields;
        },

        /**
         * Returns the feature layer holding the items.
         * @return {object} Feature layer
         */
        getItemLayer: function () {
            return this._itemLayer;
        },

        /**
         * Returns the table holding the comments.
         * @return {object} Table
         */
        getCommentTable: function () {
            return this._commentTable;
        },

        /**
         * Removes the protocol from a URL.
         * @param {string} url URL to modify
         * @return {string} URL with everything before "//" removed
         */
        deprotocolUrl: function (url) {
            return url.substring(url.indexOf("//"));
        },

        /**
         * Extracts the layer and loads its table from the configuration information.
         * @return {object} Deferred for notification of completed load
         */
        load: function () {
            var deferred = new Deferred();
            setTimeout(lang.hitch(this, function () {
                var commentTableURL;

                // Operational layer provides item fields and formats
                if (this.appConfig.itemInfo.itemData.operationalLayers.length === 0) {
                    deferred.reject(this.appConfig.i18n.map.missingItemsFeatureLayer);
                    return;
                }

                this._itemLayerInWebmap = this.appConfig.itemInfo.itemData.operationalLayers[0];
                this._itemLayer = this._itemLayerInWebmap.layerObject;
                if (!this._itemLayerInWebmap) {
                    deferred.reject(this.appConfig.i18n.map.missingItemsFeatureLayer);
                    return;
                }

                // Provides _itemFields[n].{alias, editable, length, name, nullable, type} after adjusting
                // to the presence of editing and visibility controls in the optional popup
                this._itemFields = this.applyWebmapControlsToFields(
                    this._itemLayer.fields,
                    this._itemLayerInWebmap.popupInfo
                );

                // Related table provides comment fields and formats
                this._commentTableInWebmap = this.appConfig.itemInfo.itemData.tables[0];

                // Remove the protocol from the comment table's URL so that it can be loaded in
                // http or https environments
                commentTableURL = this.deprotocolUrl(this._commentTableInWebmap.url);

                // Fetch the related table for the comments
                this._commentTable = new FeatureLayer(commentTableURL);
                on.once(this._commentTable, "load", lang.hitch(this, function (evt) {

                    // Provides _commentFields[n].{alias, editable, length, name, nullable, type} after adjusting
                    // to the presence of editing and visibility controls in the optional popup
                    this._commentFields = this.applyWebmapControlsToFields(
                        this._commentTable.fields,
                        this._commentTableInWebmap.popupInfo
                    );

                    // Formatting of comment display
                    if (this._commentTableInWebmap.popupInfo) {
                        this._commentPopupTemplate = new PopupTemplate(this._commentTableInWebmap.popupInfo);
                    } else {
                        this._commentPopupTemplate = new InfoTemplate();
                    }

                    // Override related record check from the point of view of the comments
                    // table--it's not needed
                    if (this._commentPopupTemplate._getRelatedRecords) {
                        this._commentPopupTemplate._getRelatedRecords = function () {
                            var def = new Deferred();
                            def.resolve();
                            return def.promise;
                        };
                    }

                    // Test that the items layer is related to the comments table and that
                    // the two are not involved in any other relationships
                    if (!this._itemLayer.relationships || !this._commentTable.relationships ||
                            this._itemLayer.relationships.length !== 1 ||
                            this._commentTable.relationships.length !== 1 ||
                            this._itemLayer.relationships[0].relatedTableId !== this._commentTable.layerId ||
                            this._itemLayer.layerId !== this._commentTable.relationships[0].relatedTableId) {
                        deferred.reject(this.appConfig.i18n.map.unsupportedRelationship);
                    }
                    this._primaryKeyField = this._itemLayer.relationships[0].keyField;
                    this._foreignKeyField = this._commentTable.relationships[0].keyField;

                    deferred.resolve();
                }), lang.hitch(this, function () {
                    deferred.reject(this.appConfig.i18n.map.missingCommentsTable);
                }));
            }));
            return deferred;
        },

        /**
         * Amends fields in fields list with popup editing and visibility settings.
         * @param {array} fields Fields associated with layer or table
         * @param {object} [webmapPopup] Popup associated with layer or table
         * @return {array} Amends list with "dtIsEditable" and "dtIsVisible"; if webmapPopup or its fieldInfos
         * property are undefined, dtIsEditable is a copy of "editable" and dtIsVisible is true; otherwise,
         * dtIsEditable is a copy of the popup's fieldInfo's "isEditable" and dtIsVisible is a copy of its
         * "visible" (we have to use dtIs* to avoid conflicts with the API's use of "editable")
         */
        applyWebmapControlsToFields: function (fields, webmapPopup) {
            var fieldInfos = webmapPopup ? webmapPopup.fieldInfos : null;
            array.forEach(fields, function (field) {
                // Cover no-popup and unmatched fieldname cases
                field.dtIsEditable = field.editable;
                field.dtIsVisible = true;
                field.dtStringFieldOption = null;
                field.dtTooltip = null;

                // If we have a popup, seek to update settings
                if (fieldInfos) {
                    array.some(fieldInfos, function (fieldInfo) {
                        if (field.name === fieldInfo.fieldName) {
                            field.dtIsEditable = fieldInfo.isEditable;
                            field.dtIsVisible = fieldInfo.visible;
                            field.dtStringFieldOption = fieldInfo.stringFieldOption;
                            field.dtTooltip = fieldInfo.tooltip;
                            return true;
                        }
                        return false;
                    });
                }
            });
            return fields;
        },

        /**
         * Retrieves the items within the map extent.
         * @param {Extent} [extent] Outer bounds of items to retrieve
         * @return {publish} "updatedItemsList" with results of query
         */
        queryItems: function (extent) {
            var updateQuery = new Query();
            updateQuery.where = "1=1";
            updateQuery.returnGeometry = true;
            updateQuery.orderByFields = [this._itemLayer.objectIdField + " DESC"];
            updateQuery.outFields = ["*"];
            if (extent) {
                updateQuery.geometry = extent;
            }

            this._itemLayer.queryFeatures(updateQuery, lang.hitch(this, function (results) {
                topic.publish("updatedItemsList", results ? results.features : []);
            }), lang.hitch(this, function (err) {
                console.log(err.message || "queryFeatures");
            }));
        },

        /**
         * Adds a comment to the comment table.
         * @param {string} item Item associated with this comment
         * @param {object} comment Comment as a set of attributes to be added for the item
         * @return {publish} "commentAdded" with the item associated with this comment
         * or "commentAddFailed" with an error message
         */
        addComment: function (item, comment) {
            var attr, gra;

            // Amend a copy of the comment with the foreign key pointing to the
            // associated item
            attr = lang.clone(comment);
            attr[this._foreignKeyField] = item.attributes[this._primaryKeyField];

            // Add the comment to the comment table
            gra = new Graphic(null, null, attr);
            this._commentTable.applyEdits([gra], null, null,
                lang.hitch(this, function (results) {
                    if (results.length === 0) {
                        topic.publish("commentAddFailed", "missing field");  //???
                    } else if (results[0].error) {
                        topic.publish("commentAddFailed", results[0].error);
                    } else {
                        topic.publish("commentAdded", item);
                    }
                }),
                lang.hitch(this, function (err) {
                    topic.publish("commentAddFailed", err.message || "commentAddFailed");
                }));
        },

        /**
         * Retrieves the attachments associated with an item.
         * @param {objectID} item Item whose attachments are sought
         * @return {publish} "updatedAttachments" with results of query
         */
        queryAttachments: function (item) {
            this._itemLayer.queryAttachmentInfos(
                item.attributes[this._itemLayer.objectIdField],
                lang.hitch(this, function (attachments) {
                    topic.publish("updatedAttachments", attachments);
                }),
                lang.hitch(this, function (err) {
                    console.log(err.message || "queryAttachmentInfos");  //???
                })
            );
        },

        /**
         * Retrieves the comments associated with an item.
         * @param {objectID} item Item whose comments are sought
         * @return {publish} "updatedCommentsList" with results of query
         */
        queryComments: function (item) {
            var updateQuery = new RelationshipQuery();
            updateQuery.objectIds = [item.attributes[this._itemLayer.objectIdField]];
            updateQuery.returnGeometry = true;
            updateQuery.outFields = ["*"];
            updateQuery.relationshipId = 0;

            this._itemLayer.queryRelatedFeatures(updateQuery, lang.hitch(this, function (results) {
                var pThis = this, fset, i, features;

                // Function for descending-OID-order sort
                function sortByOID(a, b) {
                    if (a.attributes[pThis._commentTable.objectIdField] > b.attributes[pThis._commentTable.objectIdField]) {
                        return -1;  // order a before b
                    }
                    if (a.attributes[pThis._commentTable.objectIdField] < b.attributes[pThis._commentTable.objectIdField]) {
                        return 1;  // order b before a
                    }
                    return 0;  // a & b have same date, so relative order doesn't matter
                }

                fset = results[item.attributes[this._itemLayer.objectIdField]];
                features = fset ? fset.features : [];

                if (features.length > 0) {
                    // Sort by descending OID order
                    features.sort(sortByOID);

                    // Add the comment table popup
                    for (i = 0; i < features.length; ++i) {
                        features[i].setInfoTemplate(this._commentPopupTemplate);
                    }
                }
                topic.publish("updatedCommentsList", features);
            }), lang.hitch(this, function (err) {
                console.log(err.message || "queryRelatedFeatures");  //???
            }));
        },

        /**
         * Updates the vote count in an item.
         * @param {object} item Item to be updated
         * @return {object} Deferred for notification of completed update
         */
        refreshVoteCount: function (item) {
            var updateQuery, updateQueryTask, deferred = new Deferred();

            // Get the latest vote count from the server, not just the feature layer
            updateQuery = new Query();
            updateQuery.objectIds = [item.attributes[this._itemLayer.objectIdField]];
            updateQuery.returnGeometry = false;
            updateQuery.outFields = [this.appConfig.itemVotesField];

            updateQueryTask = new QueryTask(this._itemLayer.url);
            updateQueryTask.execute(updateQuery, lang.hitch(this, function (results) {
                var retrievedVotes;
                if (results && results.features && results.features.length > 0) {
                    retrievedVotes = results.features[0].attributes[this.appConfig.itemVotesField];
                    if (retrievedVotes) {
                        item.attributes[this.appConfig.itemVotesField] = retrievedVotes;
                        deferred.resolve(item);
                    }
                }
                deferred.reject(item);
            }), function () {
                deferred.reject(item);
            });

            return deferred;
        },

        /**
         * Increments the designated "votes" field for the specified item.
         * @param {object} item Item to update
         * @return {publish} "voteUpdated" with updated item
         */
        incrementVote: function (item) {
            if (this.appConfig.itemVotesField.length > 0) {
                // Get the latest vote count
                this.refreshVoteCount(item).then(lang.hitch(this, function (item) {
                    // Increment the vote
                    item.attributes[this.appConfig.itemVotesField] = item.attributes[this.appConfig.itemVotesField] + 1;

                    // Update the item in the feature layer
                    this._itemLayer.applyEdits(null, [item], null, lang.hitch(this, function (ignore, updates) {
                        if (updates.length === 0) {
                            topic.publish("voteUpdateFailed", "missing field");
                        } else if (updates[0].error) {
                            topic.publish("voteUpdateFailed", updates[0].error);
                        } else {
                            topic.publish("voteUpdated", item);
                        }
                    }), lang.hitch(this, function (err) {
                        topic.publish("voteUpdateFailed", err.message || "voteUpdateFailed");
                    }));
                }), function (err) {
                    topic.publish("voteUpdateFailed", err.message || "voteUpdateFailed");
                });
            }
        }

    });

    //========================================================================================================================//

});
<commit_msg>Use the popup field aliases as comment form field labels<commit_after>/*global define,dojo,console */
/*jslint browser:true,sloppy:true,nomen:true,unparam:true,plusplus:true */
/*
 | Copyright 2014 Esri
 |
 | 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.
 */
//============================================================================================================================//
define([
    "dojo/_base/declare",
    "dojo/_base/array",
    "dojo/_base/lang",
    "dojo/Deferred",
    "dojo/json",
    "dojo/on",
    "dojo/topic",
    "esri/dijit/PopupTemplate",
    "esri/graphic",
    "esri/InfoTemplate",
    "esri/layers/FeatureLayer",
    "esri/tasks/query",
    "esri/tasks/QueryTask",
    "esri/tasks/RelationshipQuery",
    "dojo/domReady!"
], function (
    declare,
    array,
    lang,
    Deferred,
    JSON,
    on,
    topic,
    PopupTemplate,
    Graphic,
    InfoTemplate,
    FeatureLayer,
    Query,
    QueryTask,
    RelationshipQuery
) {

    //========================================================================================================================//

    return declare([], {
        appConfig: null,

        /**
         * Encapsulates the management of a layer and its related table.
         * @param {object} config Application configuration
         * @constructor
         */
        constructor: function (config) {
            this.appConfig = config;
        },

        /**
         * Returns the fields of the feature layer holding the items.
         * @return {array} List of fields
         */
        getItemFields: function () {
            return this._itemFields;
        },

        /**
         * Returns the fields of the table holding the comments.
         * @return {array} List of fields
         */
        getCommentFields: function () {
            return this._commentFields;
        },

        /**
         * Returns the feature layer holding the items.
         * @return {object} Feature layer
         */
        getItemLayer: function () {
            return this._itemLayer;
        },

        /**
         * Returns the table holding the comments.
         * @return {object} Table
         */
        getCommentTable: function () {
            return this._commentTable;
        },

        /**
         * Removes the protocol from a URL.
         * @param {string} url URL to modify
         * @return {string} URL with everything before "//" removed
         */
        deprotocolUrl: function (url) {
            return url.substring(url.indexOf("//"));
        },

        /**
         * Extracts the layer and loads its table from the configuration information.
         * @return {object} Deferred for notification of completed load
         */
        load: function () {
            var deferred = new Deferred();
            setTimeout(lang.hitch(this, function () {
                var commentTableURL;

                // Operational layer provides item fields and formats
                if (this.appConfig.itemInfo.itemData.operationalLayers.length === 0) {
                    deferred.reject(this.appConfig.i18n.map.missingItemsFeatureLayer);
                    return;
                }

                this._itemLayerInWebmap = this.appConfig.itemInfo.itemData.operationalLayers[0];
                this._itemLayer = this._itemLayerInWebmap.layerObject;
                if (!this._itemLayerInWebmap) {
                    deferred.reject(this.appConfig.i18n.map.missingItemsFeatureLayer);
                    return;
                }

                // Provides _itemFields[n].{alias, editable, length, name, nullable, type} after adjusting
                // to the presence of editing and visibility controls in the optional popup
                this._itemFields = this.applyWebmapControlsToFields(
                    this._itemLayer.fields,
                    this._itemLayerInWebmap.popupInfo
                );

                // Related table provides comment fields and formats
                this._commentTableInWebmap = this.appConfig.itemInfo.itemData.tables[0];

                // Remove the protocol from the comment table's URL so that it can be loaded in
                // http or https environments
                commentTableURL = this.deprotocolUrl(this._commentTableInWebmap.url);

                // Fetch the related table for the comments
                this._commentTable = new FeatureLayer(commentTableURL);
                on.once(this._commentTable, "load", lang.hitch(this, function (evt) {

                    // Provides _commentFields[n].{alias, editable, length, name, nullable, type} after adjusting
                    // to the presence of editing and visibility controls in the optional popup
                    this._commentFields = this.applyWebmapControlsToFields(
                        this._commentTable.fields,
                        this._commentTableInWebmap.popupInfo
                    );

                    // Formatting of comment display
                    if (this._commentTableInWebmap.popupInfo) {
                        this._commentPopupTemplate = new PopupTemplate(this._commentTableInWebmap.popupInfo);
                    } else {
                        this._commentPopupTemplate = new InfoTemplate();
                    }

                    // Override related record check from the point of view of the comments
                    // table--it's not needed
                    if (this._commentPopupTemplate._getRelatedRecords) {
                        this._commentPopupTemplate._getRelatedRecords = function () {
                            var def = new Deferred();
                            def.resolve();
                            return def.promise;
                        };
                    }

                    // Test that the items layer is related to the comments table and that
                    // the two are not involved in any other relationships
                    if (!this._itemLayer.relationships || !this._commentTable.relationships ||
                            this._itemLayer.relationships.length !== 1 ||
                            this._commentTable.relationships.length !== 1 ||
                            this._itemLayer.relationships[0].relatedTableId !== this._commentTable.layerId ||
                            this._itemLayer.layerId !== this._commentTable.relationships[0].relatedTableId) {
                        deferred.reject(this.appConfig.i18n.map.unsupportedRelationship);
                    }
                    this._primaryKeyField = this._itemLayer.relationships[0].keyField;
                    this._foreignKeyField = this._commentTable.relationships[0].keyField;

                    deferred.resolve();
                }), lang.hitch(this, function () {
                    deferred.reject(this.appConfig.i18n.map.missingCommentsTable);
                }));
            }));
            return deferred;
        },

        /**
         * Amends fields in fields list with popup editing and visibility settings.
         * @param {array} fields Fields associated with layer or table
         * @param {object} [webmapPopup] Popup associated with layer or table
         * @return {array} Amends list with "dtIsEditable" and "dtIsVisible"; if webmapPopup or its fieldInfos
         * property are undefined, dtIsEditable is a copy of "editable" and dtIsVisible is true; otherwise,
         * dtIsEditable is a copy of the popup's fieldInfo's "isEditable" and dtIsVisible is a copy of its
         * "visible" (we have to use dtIs* to avoid conflicts with the API's use of "editable")
         */
        applyWebmapControlsToFields: function (fields, webmapPopup) {
            var fieldInfos = webmapPopup ? webmapPopup.fieldInfos : null;
            array.forEach(fields, function (field) {
                // Cover no-popup and unmatched fieldname cases
                field.dtIsEditable = field.editable;
                field.dtIsVisible = true;
                field.dtStringFieldOption = null;
                field.dtTooltip = null;

                // If we have a popup, seek to update settings
                if (fieldInfos) {
                    array.some(fieldInfos, function (fieldInfo) {
                        if (field.name === fieldInfo.fieldName) {
                            if (fieldInfo.label) {
                                field.alias = fieldInfo.label;
                            }
                            field.dtIsEditable = fieldInfo.isEditable;
                            field.dtIsVisible = fieldInfo.visible;
                            field.dtStringFieldOption = fieldInfo.stringFieldOption;
                            field.dtTooltip = fieldInfo.tooltip;
                            return true;
                        }
                        return false;
                    });
                }
            });
            return fields;
        },

        /**
         * Retrieves the items within the map extent.
         * @param {Extent} [extent] Outer bounds of items to retrieve
         * @return {publish} "updatedItemsList" with results of query
         */
        queryItems: function (extent) {
            var updateQuery = new Query();
            updateQuery.where = "1=1";
            updateQuery.returnGeometry = true;
            updateQuery.orderByFields = [this._itemLayer.objectIdField + " DESC"];
            updateQuery.outFields = ["*"];
            if (extent) {
                updateQuery.geometry = extent;
            }

            this._itemLayer.queryFeatures(updateQuery, lang.hitch(this, function (results) {
                topic.publish("updatedItemsList", results ? results.features : []);
            }), lang.hitch(this, function (err) {
                console.log(err.message || "queryFeatures");
            }));
        },

        /**
         * Adds a comment to the comment table.
         * @param {string} item Item associated with this comment
         * @param {object} comment Comment as a set of attributes to be added for the item
         * @return {publish} "commentAdded" with the item associated with this comment
         * or "commentAddFailed" with an error message
         */
        addComment: function (item, comment) {
            var attr, gra;

            // Amend a copy of the comment with the foreign key pointing to the
            // associated item
            attr = lang.clone(comment);
            attr[this._foreignKeyField] = item.attributes[this._primaryKeyField];

            // Add the comment to the comment table
            gra = new Graphic(null, null, attr);
            this._commentTable.applyEdits([gra], null, null,
                lang.hitch(this, function (results) {
                    if (results.length === 0) {
                        topic.publish("commentAddFailed", "missing field");  //???
                    } else if (results[0].error) {
                        topic.publish("commentAddFailed", results[0].error);
                    } else {
                        topic.publish("commentAdded", item);
                    }
                }),
                lang.hitch(this, function (err) {
                    topic.publish("commentAddFailed", err.message || "commentAddFailed");
                }));
        },

        /**
         * Retrieves the attachments associated with an item.
         * @param {objectID} item Item whose attachments are sought
         * @return {publish} "updatedAttachments" with results of query
         */
        queryAttachments: function (item) {
            this._itemLayer.queryAttachmentInfos(
                item.attributes[this._itemLayer.objectIdField],
                lang.hitch(this, function (attachments) {
                    topic.publish("updatedAttachments", attachments);
                }),
                lang.hitch(this, function (err) {
                    console.log(err.message || "queryAttachmentInfos");  //???
                })
            );
        },

        /**
         * Retrieves the comments associated with an item.
         * @param {objectID} item Item whose comments are sought
         * @return {publish} "updatedCommentsList" with results of query
         */
        queryComments: function (item) {
            var updateQuery = new RelationshipQuery();
            updateQuery.objectIds = [item.attributes[this._itemLayer.objectIdField]];
            updateQuery.returnGeometry = true;
            updateQuery.outFields = ["*"];
            updateQuery.relationshipId = 0;

            this._itemLayer.queryRelatedFeatures(updateQuery, lang.hitch(this, function (results) {
                var pThis = this, fset, i, features;

                // Function for descending-OID-order sort
                function sortByOID(a, b) {
                    if (a.attributes[pThis._commentTable.objectIdField] > b.attributes[pThis._commentTable.objectIdField]) {
                        return -1;  // order a before b
                    }
                    if (a.attributes[pThis._commentTable.objectIdField] < b.attributes[pThis._commentTable.objectIdField]) {
                        return 1;  // order b before a
                    }
                    return 0;  // a & b have same date, so relative order doesn't matter
                }

                fset = results[item.attributes[this._itemLayer.objectIdField]];
                features = fset ? fset.features : [];

                if (features.length > 0) {
                    // Sort by descending OID order
                    features.sort(sortByOID);

                    // Add the comment table popup
                    for (i = 0; i < features.length; ++i) {
                        features[i].setInfoTemplate(this._commentPopupTemplate);
                    }
                }
                topic.publish("updatedCommentsList", features);
            }), lang.hitch(this, function (err) {
                console.log(err.message || "queryRelatedFeatures");  //???
            }));
        },

        /**
         * Updates the vote count in an item.
         * @param {object} item Item to be updated
         * @return {object} Deferred for notification of completed update
         */
        refreshVoteCount: function (item) {
            var updateQuery, updateQueryTask, deferred = new Deferred();

            // Get the latest vote count from the server, not just the feature layer
            updateQuery = new Query();
            updateQuery.objectIds = [item.attributes[this._itemLayer.objectIdField]];
            updateQuery.returnGeometry = false;
            updateQuery.outFields = [this.appConfig.itemVotesField];

            updateQueryTask = new QueryTask(this._itemLayer.url);
            updateQueryTask.execute(updateQuery, lang.hitch(this, function (results) {
                var retrievedVotes;
                if (results && results.features && results.features.length > 0) {
                    retrievedVotes = results.features[0].attributes[this.appConfig.itemVotesField];
                    if (retrievedVotes) {
                        item.attributes[this.appConfig.itemVotesField] = retrievedVotes;
                        deferred.resolve(item);
                    }
                }
                deferred.reject(item);
            }), function () {
                deferred.reject(item);
            });

            return deferred;
        },

        /**
         * Increments the designated "votes" field for the specified item.
         * @param {object} item Item to update
         * @return {publish} "voteUpdated" with updated item
         */
        incrementVote: function (item) {
            if (this.appConfig.itemVotesField.length > 0) {
                // Get the latest vote count
                this.refreshVoteCount(item).then(lang.hitch(this, function (item) {
                    // Increment the vote
                    item.attributes[this.appConfig.itemVotesField] = item.attributes[this.appConfig.itemVotesField] + 1;

                    // Update the item in the feature layer
                    this._itemLayer.applyEdits(null, [item], null, lang.hitch(this, function (ignore, updates) {
                        if (updates.length === 0) {
                            topic.publish("voteUpdateFailed", "missing field");
                        } else if (updates[0].error) {
                            topic.publish("voteUpdateFailed", updates[0].error);
                        } else {
                            topic.publish("voteUpdated", item);
                        }
                    }), lang.hitch(this, function (err) {
                        topic.publish("voteUpdateFailed", err.message || "voteUpdateFailed");
                    }));
                }), function (err) {
                    topic.publish("voteUpdateFailed", err.message || "voteUpdateFailed");
                });
            }
        }

    });

    //========================================================================================================================//

});
<|endoftext|>


<commit_before>define([
    "zepto",
    "modules/channels/EventEmitter",
    "modules/cryptography/diffie-hellman-leemon",
    "modules/data-types/hex",
    "modules/data-types/bitArray",
    "modules/data-types/bytes",
    "modules/cryptography/sha1-crypto-js",
    "modules/cryptography/aes-sjcl",
    "tools/invariant",
    "modules/data-types/isMultivalue",
    "modules/serialization/packet",
    "modules/converters/customTypes"
], function ($, EventEmitter, DiffieHellman, Hex, BitArray, Bytes, SHA1, Aes, invariant, isMultivalue, SerializationPacket) {
    "use strict";

    var dhPrivBitLength = 160;

    function hash(value) {
        return SHA1(value.as(Hex)).as(BitArray).bitSlice(0, 128);
    }

    // tl channel that is used during key exchange (while channel is being set up)
    function Tlke() {
        this.state = Tlke.STATE_NOT_STARTED;
        this._defineEvent("changeState");
        this._defineEvent("offer");
        this._defineEvent("auth");
        this._defineEvent("dirty");
        this._defineEvent("addr");
        this._defineEvent("packet");
        this._defineEvent("keyReady");
    }

    Tlke.authBitLength = 16;
    Tlke.offerBitLength = 128;

    Tlke.prototype = new EventEmitter();
    $.extend(Tlke.prototype, {

        generate: function () {
            this.checkEventHandlers();
            invariant(this.state === Tlke.STATE_NOT_STARTED,
                "Can't generate offer being in a state %s", this.state);
            this._generateOffer();
        },
        enterOffer: function (offer) {
            this.checkEventHandlers();
            invariant(isMultivalue(offer), "offer must be multivalue");
            invariant(this.state === Tlke.STATE_NOT_STARTED,
                "Can't accept offer being in a state %s", this.state);
            invariant(offer, "Received an empty offer");
            this._acceptOffer(offer);
        },
        enterAuth: function (auth) {
            invariant(isMultivalue(auth), "offer must be multivalue");
            invariant(auth, "Received an empty auth");
            this._acceptAuth(auth);
        },

        processPacket: function (bytes) {
            invariant(isMultivalue(bytes), "bytes must be multivalue");
            switch (this.state) {
            case Tlke.STATE_AWAITING_OFFER_RESPONSE:
                this._acceptOfferResponse(bytes);
                break;
            case Tlke.STATE_AWAITING_AUTH_RESPONSE:
                this._acceptAuthResponse(bytes);
                break;
            case Tlke.STATE_AWAITING_OFFER:
                this._acceptOfferData(bytes);
                break;
            case Tlke.STATE_AWAITING_AUTH:
                this._acceptAuthData(bytes);
                break;
            default:
                break;
            }
            this._onDirty();
        },

        _encrypt: function (bytes, customKey) {
            var iv = this._getRandomBytes(128);
            var aes = new Aes(customKey || this.dhAesKey);
            var encryptedData = aes.encryptCbc(bytes, iv);
            return iv.as(Bytes).concat(encryptedData);
        },

        _decrypt: function (bytes, customKey) {
            var dataBitArray = bytes.as(BitArray);
            var iv = dataBitArray.bitSlice(0, 128);
            var encryptedData = dataBitArray.bitSlice(128, dataBitArray.bitLength());
            var aes = new Aes(customKey || this.dhAesKey);
            return aes.decryptCbc(encryptedData, iv);
        },

        // Alice 1.1 (instantiation)
        _generateOffer: function () {
            this.dh = DiffieHellman.generate(dhPrivBitLength, this.random);
            var dhAes = this._getRandomBytes(Tlke.offerBitLength);
            this.dhAesKey = dhAes;
            var outId = dhAes.bitSlice(0, 16);
            var inId = dhAes.bitSlice(16, 32);
            // emit this event before any "packet" event call to configure the appropriate transport behavior
            this.fire("addr", {inId: inId, outId: outId});
            this.state = Tlke.STATE_AWAITING_OFFER_RESPONSE;
            this._onChangeState();
            this.fire("offer", this.dhAesKey);
            this.fire("packet", this._getOfferData());
            this._onDirty();
        },

        // Bob 2.1 (instantiation) offer is from getOffer (via IM)
        _acceptOffer: function (offer) {
            this.dh = DiffieHellman.generate(dhPrivBitLength, this.random);
            var dhAes = offer.as(Hex).as(BitArray);
            this.dhAesKey = dhAes;
            var inId = dhAes.bitSlice(0, 16);
            var outId = dhAes.bitSlice(16, 32);
            this.fire("addr", {inId: inId, outId: outId});
            this.state = Tlke.STATE_AWAITING_OFFER;
            this._onChangeState();
            this._onDirty();
        },

        _getOfferData: function () {
            var dhData = new Hex(this.dh.createKeyExchange());
            return this._encrypt(dhData);
        },

        // Bob 2.2.
        _acceptOfferData: function (bytes) {
            try {
                var dhData = this._decrypt(bytes);
            } catch (ex) {
                console.warn("Received bad bytes.  " + ex.message);
                return;
            }
            var dhDataHex = dhData.as(Hex).value;
            var dhkHex = this.dh.decryptKeyExchange(dhDataHex);
            this.dhk = new Hex(dhkHex);
            this.state = Tlke.STATE_AWAITING_AUTH;
            this._onChangeState();
            this.fire("packet", this._getOfferResponse());
            this.fire("auth", null);
        },

        _getOfferResponse: function () {
            var dhData = new Hex(this.dh.createKeyExchange());
            return this._encrypt(dhData);
        },

        // Alice 3.1
        _acceptOfferResponse: function (data) {
            try {
                var dhDataHex = this._decrypt(data).as(Hex).value;
            } catch (ex) {
                console.warn("Received bad bytes.  " + ex.message);
                return;
            }
            var dhkHex = this.dh.decryptKeyExchange(dhDataHex);
            this.dhk = new Hex(dhkHex);

            this.auth = this._getRandomBytes(Tlke.authBitLength);
            this.check = this._getRandomBytes(128);
            this.state = Tlke.STATE_AWAITING_AUTH_RESPONSE;
            this._onChangeState();
            this.fire("packet", this._getAuthData());
            this.fire("auth", this.auth);
        },

        _getAuthData: function () {
            return this._encrypt(this.check, this._getVerifiedDhk());
        },

        _getVerifiedDhk: function () {
            var dhk = this.dhk.as(Bytes);
            var auth = this.auth.as(Bytes);
            return hash(dhk.concat(auth));
        },

        // Bob 4.2
        _acceptAuthData: function (bytes) {
            this.authData = bytes;
            if (this.auth) {
                this._acceptAuthAndData();
            }
        },

        // Bob 4.1
        _acceptAuth: function (auth) {
            this.auth = auth;
            if (this.authData) {
                this._acceptAuthAndData();
            }
            this._onDirty();
        },

        // Bob 4.3 (4.1 + 4.2)
        _acceptAuthAndData: function () {
            var bytes = this.authData;
            // todo check's checksum and ACHTUNG if not match
            var verified = this._getVerifiedDhk();
            try {
                this.check = this._decrypt(bytes, verified);
            } catch (ex) {
                console.warn("Received bad bytes.  " + ex.message);
                return;
            }
            this.state = Tlke.STATE_CONNECTION_ESTABLISHED;
            this._onChangeState();
            this.fire("packet", this._getAuthResponse());
            var hCheck = hash(this.check);
            this.fire("keyReady", {
                inId: hCheck.bitSlice(0, 16),
                outId: hCheck.bitSlice(16, 32),
                key: hash(this.check.as(Bytes).concat(verified))
            });
            this._onDirty();
        },

        _getAuthResponse: function () {
            var hCheck = hash(this.check);
            return this._encrypt(hCheck, this._getVerifiedDhk());
        },

        // Alice 5
        _acceptAuthResponse: function (bytes) {
            var verified = this._getVerifiedDhk();
            try {
                var hCheck = this._decrypt(bytes, verified);
            } catch (ex) {
                console.warn("Received bad bytes.  " + ex.message);
                return;
            }
            if (hash(this.check).as(Hex).value !== hCheck.as(Hex).value) {
                this.state = Tlke.STATE_CONNECTION_FAILED;
                this._onChangeState();
                return;
            }
            this.state = Tlke.STATE_CONNECTION_ESTABLISHED;
            this._onChangeState();
            this.fire("keyReady", {
                inId: hCheck.bitSlice(16, 32),
                outId: hCheck.bitSlice(0, 16),
                key: hash(this.check.as(Bytes).concat(verified))
            });
        },

        _onChangeState: function () {
            this.fire("changeState", this.state);
        },

        _onDirty: function () {
            this.fire("dirty");
        },

        _getRandomBytes: function (bitLength) {
            invariant(this.random, "No valid rng is set");
            return this.random.bitArray(bitLength);
        },
        // IRng: multivalue bitArray(bitLength)
        setRng: function (rng) {
            invariant(rng && $.isFunction(rng.bitArray), "rng is not implementing IRng");
            this.random = rng;
        },

        _deserialize: function (packet, context) {
            var dto = packet.getData();
            this.state = dto.state;
            this.dhAesKey = dto.dhAesKey ? Hex.deserialize(dto.dhAesKey) : null;
            this.dhk = dto.dhk ? Hex.deserialize(dto.dhk) : null;
            this.dh = dto.dh ? DiffieHellman.deserialize(dto.dh) : null;
            this.auth = dto.auth ? Hex.deserialize(dto.auth) : null;
            this.check = dto.check ? Hex.deserialize(dto.check) : null;
            this.authData = dto.authData ? Hex.deserialize(dto.authData) : null;
        },

        serialize: function (context) {
            var packet = context.getPacket(this) || new SerializationPacket();
            packet.setData({
                state: this.state,
                dhAesKey: this.dhAesKey ? this.dhAesKey.as(Hex).serialize() : null,
                dhk: this.dhk ? this.dhk.as(Hex).serialize() : null,
                dh: this.dh ? this.dh.serialize() : null,
                auth: this.auth ? this.auth.as(Hex).serialize() : null,
                check: this.check ? this.check.as(Hex).serialize() : null,
                authData: this.authData ? this.authData.as(Hex).serialize() : null
            });
            context.setPacket(this, packet);
            return packet;
        }

    });

    Tlke.deserialize = function (packet, context, random) {
        invariant(packet, "packet is empty");
        invariant(context, "context is empty");
        invariant(random, "random is empty");
        return context.getObject(packet) || (function () {
            var tlke = new Tlke();
            tlke.setRng(random);
            tlke._deserialize(packet, context);
            context.setObject(packet, tlke);
            return tlke;
        }());
    };

    Tlke.STATE_NOT_STARTED = 1;
    Tlke.STATE_AWAITING_OFFER = 2;
    Tlke.STATE_AWAITING_OFFER_RESPONSE = 3;
    Tlke.STATE_AWAITING_AUTH = 4;
    Tlke.STATE_AWAITING_AUTH_RESPONSE = 5;
    Tlke.STATE_CONNECTION_ESTABLISHED = 6;
    Tlke.STATE_CONNECTION_SYNCED = 7;
    Tlke.STATE_CONNECTION_FAILED = -1;

    return Tlke;
});<commit_msg>AMD -> CommonJS style<commit_after>define(function (require, exports, module) {
    "use strict";

    var $ = require("zepto");
    var SHA1 = require("modules/cryptography/sha1-crypto-js");
    var DiffieHellman = require("modules/cryptography/diffie-hellman-leemon");
    var Hex = require("modules/data-types/hex");
    var BitArray = require("modules/data-types/bitArray");
    var Bytes = require("modules/data-types/bytes");
    var Aes = require("modules/cryptography/aes-sjcl");
    var Random = require("modules/cryptography/random");

    function hash(value) {
        return SHA1(value.as(Hex)).as(BitArray).bitSlice(0, 128);
    }

    // tl channel that is used during key exchange (while channel is being set up)
    function Tlke() {
        this.state = Tlke.STATE_NOT_STARTED;
        this._defineEvent("changeState");
        this._defineEvent("offer");
        this._defineEvent("auth");
        this._defineEvent("dirty");
        this._defineEvent("addr");
        this._defineEvent("packet");
        this._defineEvent("keyReady");
    }

    Tlke.authBitLength = 16;
    Tlke.offerBitLength = 128;
    Tlke.dhPrivBitLength = 160;

    var EventEmitter = require("modules/channels/EventEmitter");
    var invariant = require("tools/invariant");
    var isMultivalue = require("modules/data-types/isMultivalue");

    Tlke.prototype = new EventEmitter();
    $.extend(Tlke.prototype, {
        generate: function () {
            this.checkEventHandlers();
            invariant(this.state === Tlke.STATE_NOT_STARTED,
                "Can't generate offer being in a state %s", this.state);
            this._generateOffer();
        },
        enterOffer: function (offer) {
            this.checkEventHandlers();
            invariant(isMultivalue(offer), "offer must be multivalue");
            invariant(this.state === Tlke.STATE_NOT_STARTED,
                "Can't accept offer being in a state %s", this.state);
            invariant(offer, "Received an empty offer");
            this._acceptOffer(offer);
        },
        enterAuth: function (auth) {
            invariant(isMultivalue(auth), "offer must be multivalue");
            invariant(auth, "Received an empty auth");
            this._acceptAuth(auth);
        },

        processPacket: function (bytes) {
            invariant(isMultivalue(bytes), "bytes must be multivalue");
            switch (this.state) {
            case Tlke.STATE_AWAITING_OFFER_RESPONSE:
                this._acceptOfferResponse(bytes);
                break;
            case Tlke.STATE_AWAITING_AUTH_RESPONSE:
                this._acceptAuthResponse(bytes);
                break;
            case Tlke.STATE_AWAITING_OFFER:
                this._acceptOfferData(bytes);
                break;
            case Tlke.STATE_AWAITING_AUTH:
                this._acceptAuthData(bytes);
                break;
            default:
                break;
            }
            this._onDirty();
        },

        _encrypt: function (bytes, customKey) {
            var iv = this._getRandomBytes(128);
            var aes = new Aes(customKey || this.dhAesKey);
            var encryptedData = aes.encryptCbc(bytes, iv);
            return iv.as(Bytes).concat(encryptedData);
        },

        _decrypt: function (bytes, customKey) {
            var dataBitArray = bytes.as(BitArray);
            var iv = dataBitArray.bitSlice(0, 128);
            var encryptedData = dataBitArray.bitSlice(128, dataBitArray.bitLength());
            var aes = new Aes(customKey || this.dhAesKey);
            return aes.decryptCbc(encryptedData, iv);
        },

        // Alice 1.1 (instantiation)
        _generateOffer: function () {
            this.dh = DiffieHellman.generate(Tlke.dhPrivBitLength, this.random);
            var dhAes = this._getRandomBytes(Tlke.offerBitLength);
            this.dhAesKey = dhAes;
            var outId = dhAes.bitSlice(0, 16);
            var inId = dhAes.bitSlice(16, 32);
            // emit this event before any "packet" event call to configure the appropriate transport behavior
            this.fire("addr", {inId: inId, outId: outId});
            this.state = Tlke.STATE_AWAITING_OFFER_RESPONSE;
            this._onChangeState();
            this.fire("offer", this.dhAesKey);
            this.fire("packet", this._getOfferData());
            this._onDirty();
        },

        // Bob 2.1 (instantiation) offer is from getOffer (via IM)
        _acceptOffer: function (offer) {
            this.dh = DiffieHellman.generate(Tlke.dhPrivBitLength, this.random);
            var dhAes = offer.as(Hex).as(BitArray);
            this.dhAesKey = dhAes;
            var inId = dhAes.bitSlice(0, 16);
            var outId = dhAes.bitSlice(16, 32);
            this.fire("addr", {inId: inId, outId: outId});
            this.state = Tlke.STATE_AWAITING_OFFER;
            this._onChangeState();
            this._onDirty();
        },

        _getOfferData: function () {
            var dhData = new Hex(this.dh.createKeyExchange());
            return this._encrypt(dhData);
        },

        // Bob 2.2.
        _acceptOfferData: function (bytes) {
            try {
                var dhData = this._decrypt(bytes);
            } catch (ex) {
                console.warn("Received bad bytes.  " + ex.message);
                return;
            }
            var dhDataHex = dhData.as(Hex).value;
            var dhkHex = this.dh.decryptKeyExchange(dhDataHex);
            this.dhk = new Hex(dhkHex);
            this.state = Tlke.STATE_AWAITING_AUTH;
            this._onChangeState();
            this.fire("packet", this._getOfferResponse());
            this.fire("auth", null);
        },

        _getOfferResponse: function () {
            var dhData = new Hex(this.dh.createKeyExchange());
            return this._encrypt(dhData);
        },

        // Alice 3.1
        _acceptOfferResponse: function (data) {
            try {
                var dhDataHex = this._decrypt(data).as(Hex).value;
            } catch (ex) {
                console.warn("Received bad bytes.  " + ex.message);
                return;
            }
            var dhkHex = this.dh.decryptKeyExchange(dhDataHex);
            this.dhk = new Hex(dhkHex);

            this.auth = this._getRandomBytes(Tlke.authBitLength);
            this.check = this._getRandomBytes(128);
            this.state = Tlke.STATE_AWAITING_AUTH_RESPONSE;
            this._onChangeState();
            this.fire("packet", this._getAuthData());
            this.fire("auth", this.auth);
        },

        _getAuthData: function () {
            return this._encrypt(this.check, this._getVerifiedDhk());
        },

        _getVerifiedDhk: function () {
            var dhk = this.dhk.as(Bytes);
            var auth = this.auth.as(Bytes);
            return hash(dhk.concat(auth));
        },

        // Bob 4.2
        _acceptAuthData: function (bytes) {
            this.authData = bytes;
            if (this.auth) {
                this._acceptAuthAndData();
            }
        },

        // Bob 4.1
        _acceptAuth: function (auth) {
            this.auth = auth;
            if (this.authData) {
                this._acceptAuthAndData();
            }
            this._onDirty();
        },

        // Bob 4.3 (4.1 + 4.2)
        _acceptAuthAndData: function () {
            var bytes = this.authData;
            // todo check's checksum and ACHTUNG if not match
            var verified = this._getVerifiedDhk();
            try {
                this.check = this._decrypt(bytes, verified);
            } catch (ex) {
                console.warn("Received bad bytes.  " + ex.message);
                return;
            }
            this.state = Tlke.STATE_CONNECTION_ESTABLISHED;
            this._onChangeState();
            this.fire("packet", this._getAuthResponse());
            var hCheck = hash(this.check);
            this.fire("keyReady", {
                inId: hCheck.bitSlice(0, 16),
                outId: hCheck.bitSlice(16, 32),
                key: hash(this.check.as(Bytes).concat(verified))
            });
            this._onDirty();
        },

        _getAuthResponse: function () {
            var hCheck = hash(this.check);
            return this._encrypt(hCheck, this._getVerifiedDhk());
        },

        // Alice 5
        _acceptAuthResponse: function (bytes) {
            var verified = this._getVerifiedDhk();
            try {
                var hCheck = this._decrypt(bytes, verified);
            } catch (ex) {
                console.warn("Received bad bytes.  " + ex.message);
                return;
            }
            if (hash(this.check).as(Hex).value !== hCheck.as(Hex).value) {
                this.state = Tlke.STATE_CONNECTION_FAILED;
                this._onChangeState();
                return;
            }
            this.state = Tlke.STATE_CONNECTION_ESTABLISHED;
            this._onChangeState();
            this.fire("keyReady", {
                inId: hCheck.bitSlice(16, 32),
                outId: hCheck.bitSlice(0, 16),
                key: hash(this.check.as(Bytes).concat(verified))
            });
        },

        _onChangeState: function () {
            this.fire("changeState", this.state);
        },

        _onDirty: function () {
            this.fire("dirty");
        },

        _getRandomBytes: function (bitLength) {
            invariant(this.random, "No valid rng is set");
            return this.random.bitArray(bitLength);
        },
        // IRng: multivalue bitArray(bitLength)
        setRng: function (rng) {
            invariant(rng instanceof Random, "rng must be instanceof Random");
            this.random = rng;
        },

        deserialize: function (packet, context) {
            var dto = packet.getData();
            this.state = dto.state;
            this.dhAesKey = dto.dhAesKey ? Hex.deserialize(dto.dhAesKey) : null;
            this.dhk = dto.dhk ? Hex.deserialize(dto.dhk) : null;
            this.dh = dto.dh ? DiffieHellman.deserialize(dto.dh) : null;
            this.auth = dto.auth ? Hex.deserialize(dto.auth) : null;
            this.check = dto.check ? Hex.deserialize(dto.check) : null;
            this.authData = dto.authData ? Hex.deserialize(dto.authData) : null;
            this.random = context.deserialize(packet.getLink("random"));
        },

        serialize: function (packet, context) {
            packet.setData({
                state: this.state,
                dhAesKey: this.dhAesKey ? this.dhAesKey.as(Hex).serialize() : null,
                dhk: this.dhk ? this.dhk.as(Hex).serialize() : null,
                dh: this.dh ? this.dh.serialize() : null,
                auth: this.auth ? this.auth.as(Hex).serialize() : null,
                check: this.check ? this.check.as(Hex).serialize() : null,
                authData: this.authData ? this.authData.as(Hex).serialize() : null
            });
            packet.setLink("random", context.serialize(this.random));
            return packet;
        }

    });

    Tlke.STATE_NOT_STARTED = 1;
    Tlke.STATE_AWAITING_OFFER = 2;
    Tlke.STATE_AWAITING_OFFER_RESPONSE = 3;
    Tlke.STATE_AWAITING_AUTH = 4;
    Tlke.STATE_AWAITING_AUTH_RESPONSE = 5;
    Tlke.STATE_CONNECTION_ESTABLISHED = 6;
    Tlke.STATE_CONNECTION_SYNCED = 7;
    Tlke.STATE_CONNECTION_FAILED = -1;

    module.exports = Tlke;
});<|endoftext|>


<commit_before>module.exports = {

  acidBass: {
    Q:.9,
    filterType:2,
    filterMult:4,
    cutoff:1.25,
    saturation:3.5,
    attack:1/8192,
    decay:1/10,
    octave:-3,
    glide:2000
  },

  acidBass2: {
    Q:.7,
    filterType:2,
    filterMult:3.5,
    cutoff:.5,
    saturation:10,
    attack:1/8192,
    decay:1/10,
    octave:-2,
    glide:100
  },

  'bleep.dry': {
    attack:1/256, decay:1/32,
    waveform:'sine'
  },
  'bleep': {
    attack:1/256, decay:1/32,
    waveform:'sine'
  },

  'bleep.echo': {
    waveform:'sine',
    attack:1/256, decay:1/32,
    gain:.25,
    presetInit: function( audio ) {
      this.fx.push( audio.effects.Delay({ feedback:.5, time:1/12 }) )
    }
  },

  shimmer: {
    attack:1/128, decay:2,
    waveform:'pwm',
    filterType:1,
    cutoff:1,
    filterMult:1,
    Q:.6,
    maxVoices:3,
    gain:.1,
    antialias:false,
    presetInit: function( audio ) {
      this.fx.add( audio.effects.Chorus('warbly') )
      this.pwmod = audio.Gen.make( audio.Gen.ugens.mul( audio.Gen.ugens.cycle(8), .275 ) )
      this.pwmod.connect( this.pulsewidth )
    }
  },

  stringPad: {
    attack:1/2, decay:1.5, gain:.015,
    presetInit: function( audio ) {
      this.fx.chorus = audio.effects.Chorus('lush')
      this.fx.add( this.fx.chorus  )
    }
  },

  cry: {
    attack:1/2, decay:1.5, gain:.045,
    panVoices:true,
    presetInit: function( audio ) {
      this.chorus = audio.effects.Chorus('lush')
      this.fx.add( this.chorus  )
      this.bitCrusher = audio.effects.BitCrusher({ bitDepth:.5 })
      this.fx.add( this.bitCrusher )
      // gen( .5 + cycle( btof(16) ) * .35
      this.srmod = audio.Gen.make( audio.Gen.ugens.add( .5, audio.Gen.ugens.mul( audio.Gen.ugens.cycle(.125/2), .35 ) ) )
      this.bitCrusher.sampleRate = this.srmod
      this.delay = audio.effects.Delay({ time:1/6, feedback:.75 })
      this.fx.add( this.delay )
    }
  },

  brass: {
    attack:1/6, decay:1.5, gain:.05,
    filterType:1, Q:.5575, cutoff:2,
    presetInit: function( audio ) {
      this.fx.add( audio.effects.Chorus('lush') )
      this.chorus = this.fx[0]
    }
  },

  'brass.short':{
    gain:.75,
    filterType:1,
    antialias:true,
    attack:1/32,
    decay:1/16,
    filterMult:3,
    cutoff:.175,
    Q:.6
  },

  'pwm.squeak':{
    waveform:'pwm',
    attack:1/4096,
    decay:1/16,
    Q:.8,
    cutoff:.65,
    saturation:5,
    filterType:2,
    glide:500
  },

  'pwm.short':{
    attack:1/1024,
    decay:1/8,
    antialias:true,
    waveform:'pwm'
  },

  chirp: { filterType:2, cutoff:.325, decay:1/16 },

  'square.perc': {
    waveform:'square',
    shape:'exponential',
    //antialias:true,
    filterType:2,
    cutoff:.25,
    decay:1/8,
    panVoices:true
  },
}
<commit_msg>rhodes preset<commit_after>module.exports = {

  acidBass: {
    Q:.9,
    filterType:2,
    filterMult:4,
    cutoff:1.25,
    saturation:3.5,
    attack:1/8192,
    decay:1/10,
    octave:-3,
    glide:2000
  },

  acidBass2: {
    Q:.7,
    filterType:2,
    filterMult:3.5,
    cutoff:.5,
    saturation:10,
    attack:1/8192,
    decay:1/10,
    octave:-2,
    glide:100
  },

  'bleep.dry': {
    attack:1/256, decay:1/32,
    waveform:'sine'
  },
  'bleep': {
    attack:1/256, decay:1/32,
    waveform:'sine'
  },

  'bleep.echo': {
    waveform:'sine',
    attack:1/256, decay:1/32,
    gain:.25,
    presetInit: function( audio ) {
      this.fx.push( audio.effects.Delay({ feedback:.5, time:1/12 }) )
    }
  },

  shimmer: {
    attack:1/128, decay:2,
    waveform:'pwm',
    filterType:1,
    cutoff:1,
    filterMult:1,
    Q:.6,
    maxVoices:3,
    gain:.1,
    antialias:false,
    presetInit: function( audio ) {
      this.fx.add( audio.effects.Chorus('warbly') )
      this.pwmod = audio.Gen.make( audio.Gen.ugens.mul( audio.Gen.ugens.cycle(8), .275 ) )
      this.pwmod.connect( this.pulsewidth )
    }
  },

  stringPad: {
    attack:1/2, decay:1.5, gain:.015,
    presetInit: function( audio ) {
      this.fx.chorus = audio.effects.Chorus('lush')
      this.fx.add( this.fx.chorus  )
    }
  },

  cry: {
    attack:1/2, decay:1.5, gain:.045,
    panVoices:true,
    presetInit: function( audio ) {
      this.chorus = audio.effects.Chorus('lush')
      this.fx.add( this.chorus  )
      this.bitCrusher = audio.effects.BitCrusher({ bitDepth:.5 })
      this.fx.add( this.bitCrusher )
      // gen( .5 + cycle( btof(16) ) * .35
      this.srmod = audio.Gen.make( audio.Gen.ugens.add( .5, audio.Gen.ugens.mul( audio.Gen.ugens.cycle(.125/2), .35 ) ) )
      this.bitCrusher.sampleRate = this.srmod
      this.delay = audio.effects.Delay({ time:1/6, feedback:.75 })
      this.fx.add( this.delay )
    }
  },

  brass: {
    attack:1/6, decay:1.5, gain:.05,
    filterType:1, Q:.5575, cutoff:2,
    presetInit: function( audio ) {
      this.fx.add( audio.effects.Chorus('lush') )
      this.chorus = this.fx[0]
    }
  },

  'brass.short':{
    gain:.75,
    filterType:1,
    antialias:true,
    attack:1/32,
    decay:1/16,
    filterMult:3,
    cutoff:.175,
    Q:.6
  },

  'pwm.squeak':{
    waveform:'pwm',
    attack:1/4096,
    decay:1/16,
    Q:.8,
    cutoff:.65,
    saturation:5,
    filterType:2,
    glide:500
  },

  'pwm.short':{
    attack:1/1024,
    decay:1/8,
    antialias:true,
    waveform:'pwm'
  },

  chirp: { filterType:2, cutoff:.325, decay:1/16 },

  'square.perc': {
    waveform:'square',
    shape:'exponential',
    //antialias:true,
    filterType:2,
    cutoff:.25,
    decay:1/8,
    panVoices:true
  },
  rhodes:{
    waveform:'sine',
    presetInit( audio ) {
      this.tremolo = audio.effects.Tremolo()
      this.fx.add( this.tremolo )
    },
    decay:4,
    shape:'exponential'
  }
}
<|endoftext|>


<commit_before>// @flow

import {
  ProductTagModel,
} from '../models'

/*
 * Assume that we query:
 *   - category by _id (default)
 *   - tag by slug. So we need a preprocess function to convert Tag slug to _id
 */
export const filters = {
  category: {
    dbField: 'categories',
    dbType: String,
    compareType: 'EQUAL',
  },
  tag: {
    dbType: String,
    compareType: 'EQUAL',
    preprocess: async (tag: string) => {
      const obj = await ProductTagModel.Model.findOne({ slug: tag }).select('_id')
      if (obj) {
        return { tags: obj._id }
      }
      return {}
    },
  },
  brand: {
    dbField: 'brands',
    dbType: String,
    compareType: 'EQUAL',
  },
}

export const populate = ['category', 'categories', 'tags', 'brands']
<commit_msg>refactor<commit_after>// @flow

import {
  ProductTagModel,
} from '../models'

/*
 * Assume that we query:
 *   - category by _id (default)
 *   - tag by slug. So we need a preprocess function to convert Tag slug to _id
 */
export const filters = {
  category: {
    dbField: 'categories',
    dbType: String,
    compareType: 'EQUAL',
  },
  tag: {
    dbType: String,
    compareType: 'EQUAL',
    preprocess: async (tag: string) => {
      const obj = await ProductTagModel.Model.findOne({ slug: tag }).select('_id')
      if (!obj) {
        return { xxx: true }
      }
      return { tags: obj._id }
    },
  },
  brand: {
    dbField: 'brands',
    dbType: String,
    compareType: 'EQUAL',
  },
}

export const populate = ['category', 'categories', 'tags', 'brands']
<|endoftext|>