<commit_before>module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-symlink');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-coffee');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-commands');

    var filesLess = {},
        filesCoffee = {};

    // Configuration
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        symlink: {
            // BOWER COMPONENT
            fontawesome_font_otf: {
                src: 'bower_components/font-awesome/fonts/FontAwesome.otf',
                dest: 'web/fonts/FontAwesome.otf'
            },
            fontawesome_font_eot: {
                src: 'bower_components/font-awesome/fonts/fontawesome-webfont.eot',
                dest: 'web/fonts/fontawesome-webfont.eot'
            },
            fontawesome_font_svg: {
                src: 'bower_components/font-awesome/fonts/fontawesome-webfont.svg',
                dest: 'web/fonts/fontawesome-webfont.svg'
            },
            fontawesome_font_ttf: {
                src: 'bower_components/font-awesome/fonts/fontawesome-webfont.ttf',
                dest: 'web/fonts/fontawesome-webfont.ttf'
            },
            fontawesome_font_woff: {
                src: 'bower_components/font-awesome/fonts/fontawesome-webfont.woff',
                dest: 'web/fonts/fontawesome-webfont.woff'
            },
            bootstrap_font_eot: {
                src: 'bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot',
                dest: 'web/fonts/glyphicons-halflings-regular.eot'
            },
            bootstrap_font_svg: {
                src: 'bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg',
                dest: 'web/fonts/glyphicons-halflings-regular.svg'
            },
            bootstrap_font_ttf: {
                src: 'bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf',
                dest: 'web/fonts/glyphicons-halflings-regular.ttf'
            },
            bootstrap_font_woff: {
                src: 'bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff',
                dest: 'web/fonts/glyphicons-halflings-regular.woff'
            },
            datatable_img_sort_asc: {
                src: 'bower_components/datatables/media/images/sort_asc.png',
                dest: 'web/images/sort_asc.png'
            },
            datatable_img_sort_both: {
                src: 'bower_components/datatables/media/images/sort_both.png',
                dest: 'web/images/sort_both.png'
            },
            datatable_img_sort_desc: {
                src: 'bower_components/datatables/media/images/sort_desc.png',
                dest: 'web/images/sort_desc.png'
            },
            pace_js: {
                src: 'bower_components/pace/pace.min.js',
                dest: 'web/js/pace.min.js'
            },

            // SMARTADMIN ASSETS
            smartadmin_bg: {
                src: 'web/bundles/phporchestrabackoffice/smartadmin/img/mybg.png',
                dest: 'web/img/mybg.png'
            },
            smartadmin_flags: {
                src: 'web/bundles/phporchestrabackoffice/smartadmin/img/flags/flags.png',
                dest: 'web/img/flags/flags.png'
            }
        },

        clean: {
            built: ["web/built"]
        },

        less: {
            bundles: {
                files: filesLess
            }
        },

        cssmin: {
            minify: {
                expand: true,
                src: ['web/css/all.css'],
                ext: '.min.css'
            }
        },

        coffee: {
            compileBare: {
                options: {
                    bare: true
                },
                files: filesCoffee
            }
        },

        uglify: {
            dist: {
                files: {
                    'web/js/all.min.js': ['web/js/all.js']
                }
            }
        },

        concat: {
            smartadminjs: {
                src: [
                    'bower_components/jquery/jquery.js',
                    'bower_components/jquery-ui/ui/jquery-ui.js',
                    'web/bundles/phporchestrabackoffice/smartadmin/js/app.config.js',
                    'bower_components/bootstrap/dist/js/bootstrap.js',
                    'web/bundles/phporchestrabackoffice/smartadmin/js/notification/SmartNotification.min.js',
                    'web/bundles/phporchestrabackoffice/smartadmin/js/smartwidgets/jarvis.widget.min.js',
                    'web/bundles/phporchestrabackoffice/smartadmin/js/app.min.js',
                ],
                dest: 'web/built/smartadmin.js'
            },

            libjs: {
                src: [
                    'bower_components/underscore/underscore.js',
                    'bower_components/backbone/backbone.js',
                    'bower_components/angular/angular.js',
                    'bower_components/datatables/media/js/jquery.dataTables.js',
                    'bower_components/jquery-form/jquery.form.js',
                    'web/bundles/phporchestrabackoffice/js/latinise.js',
                    'web/bundles/phporchestrabackoffice/js/jQuery.DOMNodeAppear.js',
                ],
                dest: 'web/built/lib.js'
            },

            orchestrajs: {
                src: [
                     'web/built/phporchestrabackoffice/js/orchestraLib.js',
                     'web/built/phporchestrabackoffice/js/orchestraListeners.js',

                     // MISC
                     'web/built/phporchestrabackoffice/js/include.js',
                     'web/built/phporchestrabackoffice/js/addPrototype.js',
                     'web/built/phporchestrabackoffice/js/modelBackbone.js',
                     'web/built/phporchestrabackoffice/js/adminFormView.js',
                     'web/built/phporchestrabackoffice/js/generateAlias.js',
                     'web/built/phporchestrabackoffice/js/page/makeSortable.js',
                     'web/built/phporchestrabackoffice/js/page/areaView.js',
                     'web/built/phporchestrabackoffice/js/page/blockView.js',
                     'web/built/phporchestrabackoffice/js/page/nodeView.js',
                     'web/built/phporchestrabackoffice/js/page/NodeVersionView.js',
                     'web/built/phporchestrabackoffice/js/page/NodeLanguageView.js',
                     'web/built/phporchestrabackoffice/js/page/previewLinkView.js',
                     'web/built/phporchestrabackoffice/js/table/TableviewView.js',
                     'web/built/phporchestrabackoffice/js/table/TableviewCollectionView.js',
                     'web/built/phporchestrabackoffice/js/FullPageFormView.js',
                     'web/built/phporchestrabackoffice/js/page/templateView.js',
                     'web/built/phporchestrabackoffice/js/page/showNode.js',
                     'web/built/phporchestrabackoffice/js/page/showTemplate.js',
                     'web/built/phporchestrabackoffice/js/table/tableviewLoader.js',
                     'web/built/phporchestrabackoffice/js/page/nodeConstructor.js',
                     'web/built/phporchestrabackoffice/js/treeAjaxDelete.js',
                     'web/built/phporchestrabackoffice/js/configurableContentFormListener.js',
                     'web/built/phporchestrabackoffice/js/page/blocksPanel.js',
                     'web/built/phporchestrabackoffice/js/security.js',

                     // MEDIATHEQUE
                     'web/built/phporchestrabackoffice/js/mediatheque/orchestraMediaType.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/mediaModalListeners.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/mediaModalView.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/mediaFormView.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/GalleryCollectionView.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/GalleryLoad.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/GalleryView.js',

                     // INDEXATION
                     'web/bundles/phporchestraindexation/js/*.js',

                     // LEXIKTRANSLATION
                     'web/bundles/lexiktranslation/ng-table/ng-table.min.js',
                     'web/built/phporchestratranslation/js/translationView.js',

                     // BACKBONE ROUTER
                     'web/bundles/phporchestrabackoffice/js/backboneRouter.js',
                ],
                dest: 'web/built/orchestra.js'
            },

            js: {
                src: [
                    'web/built/smartadmin.js',
                    'web/built/lib.js',
                    'web/built/orchestra.js'
                ],
                dest: 'web/js/all.js'
            },

            smartadmincss: {
                src: [
                    // SMARTADMIN PACKAGE
//                    'bower_components/bootstrap/dist/css/bootstrap.min.css',
                    'web/bundles/phporchestrabackoffice/smartadmin/css/bootstrap.min.css',
                    'bower_components/font-awesome/css/font-awesome.min.css',
                    'web/bundles/phporchestrabackoffice/smartadmin/css/smartadmin-production.min.css',
                    'web/bundles/phporchestrabackoffice/smartadmin/css/smartadmin-skins.min.css',

                    // ORCHESTRA SMARTADMIN PATCHES
                    'web/built/phporchestrabackoffice/css/smartadminPatches/flags.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/title.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/modal.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/widget.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/checkbox.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/tab.css',

                    // TINYMCE PATCHES
                    'web/built/phporchestrabackoffice/css/tinyMCEPatches/floatPanel.css'

                ],
                dest: 'web/built/smartadmin.css'
            },

            libcss: {
                src: [
                      'bower_components/jquery-ui/themes/base/jquery-ui.css',
                      'bower_components/datatables/media/css/jquery.dataTables.css'
                ],
                dest: 'web/built/lib.css'
            },

            orchestracss: {
                src: [
                      'web/built/phporchestrabackoffice/css/phporchestra.css',
                      'web/built/phporchestrabackoffice/css/mediatheque.css',
                      'web/built/phporchestracms/css/template.css',
                      'web/built/phporchestrabackoffice/css/blocksPanel.css',
                      'web/built/phporchestrabackoffice/css/mediaModal.css',
                      'web/bundles/lexiktranslation/ng-table/ng-table.min.css',
                      'web/built/phporchestrabackoffice/css/loginPage.css'
                ],
                dest: 'web/built/orchestra.css'
            },

            css: {
                src: [
                      'web/built/smartadmin.css',
                      'web/built/lib.css',
                      'web/built/orchestra.css'
                ],
                dest: 'web/css/all.css'
            }
        },

        watch: {
            css: {
                files: ['web/bundles/*/less/*.less'],
                tasks: ['css', 'command:assetic_dump']
            },
            javascript: {
                files: ['web/bundles/*/coffee/*.coffee'],
                tasks: ['javascript', 'command:assetic_dump']
            }
        },

        command : {
            assets_install: {
                cmd  : 'php app/console assets:install --symlink'
            },
            assetic_dump: {
                cmd  : 'php app/console assetic:dump'
            }
        }
    });

    // Default task(s).
    grunt.registerTask('default', ['clean', 'command:assets_install', 'symlink', 'css', 'javascript', 'javascriptProd', 'command:assetic_dump']);
    grunt.registerTask('css', ['less:discovering', 'less', 'concat:smartadmincss', 'concat:libcss', 'concat:orchestracss', 'concat:css', 'cssmin']);
    grunt.registerTask('javascript', ['coffee:discovering', 'coffee', 'concat:smartadminjs', 'concat:libjs', 'concat:orchestrajs', 'concat:js']);
    grunt.registerTask('javascriptProd', ['uglify']);
    grunt.registerTask('less:discovering', 'This is a function', function() {
        // LESS Files management
        // Source LESS files are located inside : bundles/[bundle]/less/
        // Destination CSS files are located inside : built/[bundle]/css/
        var mappingFileLess = grunt.file.expandMapping(
            ['*/less/*.less', '*/less/*/*.less'],
            'web/built/', {
                cwd: 'web/bundles/',
                rename: function(dest, matchedSrcPath, options) {
                    return dest + matchedSrcPath.replace(/less/g, 'css');
                }
            });

        grunt.util._.each(mappingFileLess, function(value) {
            // Why value.src is an array ??
            filesLess[value.dest] = value.src[0];
        });
    });
    grunt.registerTask('coffee:discovering', 'This is a function', function() {
        // COFFEE Files management
        // Source COFFEE files are located inside : bundles/[bundle]/coffee/
        // Destination JS files are located inside : built/[bundle]/js/
        var mappingFileCoffee = grunt.file.expandMapping(
            ['*/coffee/*.coffee', '*/coffee/*/*.coffee'],
            'web/built/', {
                cwd: 'web/bundles/',
                rename: function(dest, matchedSrcPath, options) {
                    return dest + matchedSrcPath.replace(/coffee/g, 'js');
                }
            });

        grunt.util._.each(mappingFileCoffee, function(value) {
            // Why value.src is an array ??
            filesCoffee[value.dest] = value.src[0];
        });
    });
};
<commit_msg>increase content type css<commit_after>module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-symlink');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-coffee');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-commands');

    var filesLess = {},
        filesCoffee = {};

    // Configuration
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        symlink: {
            // BOWER COMPONENT
            fontawesome_font_otf: {
                src: 'bower_components/font-awesome/fonts/FontAwesome.otf',
                dest: 'web/fonts/FontAwesome.otf'
            },
            fontawesome_font_eot: {
                src: 'bower_components/font-awesome/fonts/fontawesome-webfont.eot',
                dest: 'web/fonts/fontawesome-webfont.eot'
            },
            fontawesome_font_svg: {
                src: 'bower_components/font-awesome/fonts/fontawesome-webfont.svg',
                dest: 'web/fonts/fontawesome-webfont.svg'
            },
            fontawesome_font_ttf: {
                src: 'bower_components/font-awesome/fonts/fontawesome-webfont.ttf',
                dest: 'web/fonts/fontawesome-webfont.ttf'
            },
            fontawesome_font_woff: {
                src: 'bower_components/font-awesome/fonts/fontawesome-webfont.woff',
                dest: 'web/fonts/fontawesome-webfont.woff'
            },
            bootstrap_font_eot: {
                src: 'bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.eot',
                dest: 'web/fonts/glyphicons-halflings-regular.eot'
            },
            bootstrap_font_svg: {
                src: 'bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.svg',
                dest: 'web/fonts/glyphicons-halflings-regular.svg'
            },
            bootstrap_font_ttf: {
                src: 'bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf',
                dest: 'web/fonts/glyphicons-halflings-regular.ttf'
            },
            bootstrap_font_woff: {
                src: 'bower_components/bootstrap/dist/fonts/glyphicons-halflings-regular.woff',
                dest: 'web/fonts/glyphicons-halflings-regular.woff'
            },
            datatable_img_sort_asc: {
                src: 'bower_components/datatables/media/images/sort_asc.png',
                dest: 'web/images/sort_asc.png'
            },
            datatable_img_sort_both: {
                src: 'bower_components/datatables/media/images/sort_both.png',
                dest: 'web/images/sort_both.png'
            },
            datatable_img_sort_desc: {
                src: 'bower_components/datatables/media/images/sort_desc.png',
                dest: 'web/images/sort_desc.png'
            },
            pace_js: {
                src: 'bower_components/pace/pace.min.js',
                dest: 'web/js/pace.min.js'
            },

            // SMARTADMIN ASSETS
            smartadmin_bg: {
                src: 'web/bundles/phporchestrabackoffice/smartadmin/img/mybg.png',
                dest: 'web/img/mybg.png'
            },
            smartadmin_flags: {
                src: 'web/bundles/phporchestrabackoffice/smartadmin/img/flags/flags.png',
                dest: 'web/img/flags/flags.png'
            }
        },

        clean: {
            built: ["web/built"]
        },

        less: {
            bundles: {
                files: filesLess
            }
        },

        cssmin: {
            minify: {
                expand: true,
                src: ['web/css/all.css'],
                ext: '.min.css'
            }
        },

        coffee: {
            compileBare: {
                options: {
                    bare: true
                },
                files: filesCoffee
            }
        },

        uglify: {
            dist: {
                files: {
                    'web/js/all.min.js': ['web/js/all.js']
                }
            }
        },

        concat: {
            smartadminjs: {
                src: [
                    'bower_components/jquery/jquery.js',
                    'bower_components/jquery-ui/ui/jquery-ui.js',
                    'web/bundles/phporchestrabackoffice/smartadmin/js/app.config.js',
                    'bower_components/bootstrap/dist/js/bootstrap.js',
                    'web/bundles/phporchestrabackoffice/smartadmin/js/notification/SmartNotification.min.js',
                    'web/bundles/phporchestrabackoffice/smartadmin/js/smartwidgets/jarvis.widget.min.js',
                    'web/bundles/phporchestrabackoffice/smartadmin/js/app.min.js',
                ],
                dest: 'web/built/smartadmin.js'
            },

            libjs: {
                src: [
                    'bower_components/underscore/underscore.js',
                    'bower_components/backbone/backbone.js',
                    'bower_components/angular/angular.js',
                    'bower_components/datatables/media/js/jquery.dataTables.js',
                    'bower_components/jquery-form/jquery.form.js',
                    'web/bundles/phporchestrabackoffice/js/latinise.js',
                    'web/bundles/phporchestrabackoffice/js/jQuery.DOMNodeAppear.js',
                ],
                dest: 'web/built/lib.js'
            },

            orchestrajs: {
                src: [
                     'web/built/phporchestrabackoffice/js/orchestraLib.js',
                     'web/built/phporchestrabackoffice/js/orchestraListeners.js',

                     // MISC
                     'web/built/phporchestrabackoffice/js/include.js',
                     'web/built/phporchestrabackoffice/js/addPrototype.js',
                     'web/built/phporchestrabackoffice/js/modelBackbone.js',
                     'web/built/phporchestrabackoffice/js/adminFormView.js',
                     'web/built/phporchestrabackoffice/js/generateAlias.js',
                     'web/built/phporchestrabackoffice/js/page/makeSortable.js',
                     'web/built/phporchestrabackoffice/js/page/areaView.js',
                     'web/built/phporchestrabackoffice/js/page/blockView.js',
                     'web/built/phporchestrabackoffice/js/page/nodeView.js',
                     'web/built/phporchestrabackoffice/js/page/NodeVersionView.js',
                     'web/built/phporchestrabackoffice/js/page/NodeLanguageView.js',
                     'web/built/phporchestrabackoffice/js/page/previewLinkView.js',
                     'web/built/phporchestrabackoffice/js/table/TableviewView.js',
                     'web/built/phporchestrabackoffice/js/table/TableviewCollectionView.js',
                     'web/built/phporchestrabackoffice/js/FullPageFormView.js',
                     'web/built/phporchestrabackoffice/js/page/templateView.js',
                     'web/built/phporchestrabackoffice/js/page/showNode.js',
                     'web/built/phporchestrabackoffice/js/page/showTemplate.js',
                     'web/built/phporchestrabackoffice/js/table/tableviewLoader.js',
                     'web/built/phporchestrabackoffice/js/page/nodeConstructor.js',
                     'web/built/phporchestrabackoffice/js/treeAjaxDelete.js',
                     'web/built/phporchestrabackoffice/js/configurableContentFormListener.js',
                     'web/built/phporchestrabackoffice/js/page/blocksPanel.js',
                     'web/built/phporchestrabackoffice/js/security.js',

                     // MEDIATHEQUE
                     'web/built/phporchestrabackoffice/js/mediatheque/orchestraMediaType.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/mediaModalListeners.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/mediaModalView.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/mediaFormView.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/GalleryCollectionView.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/GalleryLoad.js',
                     'web/built/phporchestrabackoffice/js/mediatheque/GalleryView.js',

                     // INDEXATION
                     'web/bundles/phporchestraindexation/js/*.js',

                     // LEXIKTRANSLATION
                     'web/bundles/lexiktranslation/ng-table/ng-table.min.js',
                     'web/built/phporchestratranslation/js/translationView.js',

                     // BACKBONE ROUTER
                     'web/bundles/phporchestrabackoffice/js/backboneRouter.js',
                ],
                dest: 'web/built/orchestra.js'
            },

            js: {
                src: [
                    'web/built/smartadmin.js',
                    'web/built/lib.js',
                    'web/built/orchestra.js'
                ],
                dest: 'web/js/all.js'
            },

            smartadmincss: {
                src: [
                    // SMARTADMIN PACKAGE
//                    'bower_components/bootstrap/dist/css/bootstrap.min.css',
                    'web/bundles/phporchestrabackoffice/smartadmin/css/bootstrap.min.css',
                    'bower_components/font-awesome/css/font-awesome.min.css',
                    'web/bundles/phporchestrabackoffice/smartadmin/css/smartadmin-production.min.css',
                    'web/bundles/phporchestrabackoffice/smartadmin/css/smartadmin-skins.min.css',

                    // ORCHESTRA SMARTADMIN PATCHES
                    'web/built/phporchestrabackoffice/css/smartadminPatches/flags.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/title.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/modal.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/widget.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/checkbox.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/tab.css',
                    'web/built/phporchestrabackoffice/css/smartadminPatches/form.css',

                    // TINYMCE PATCHES
                    'web/built/phporchestrabackoffice/css/tinyMCEPatches/floatPanel.css'

                ],
                dest: 'web/built/smartadmin.css'
            },

            libcss: {
                src: [
                      'bower_components/jquery-ui/themes/base/jquery-ui.css',
                      'bower_components/datatables/media/css/jquery.dataTables.css'
                ],
                dest: 'web/built/lib.css'
            },

            orchestracss: {
                src: [
                      'web/built/phporchestrabackoffice/css/phporchestra.css',
                      'web/built/phporchestrabackoffice/css/mediatheque.css',
                      'web/built/phporchestracms/css/template.css',
                      'web/built/phporchestrabackoffice/css/blocksPanel.css',
                      'web/built/phporchestrabackoffice/css/mediaModal.css',
                      'web/bundles/lexiktranslation/ng-table/ng-table.min.css',
                      'web/built/phporchestrabackoffice/css/loginPage.css'
                ],
                dest: 'web/built/orchestra.css'
            },

            css: {
                src: [
                      'web/built/smartadmin.css',
                      'web/built/lib.css',
                      'web/built/orchestra.css'
                ],
                dest: 'web/css/all.css'
            }
        },

        watch: {
            css: {
                files: ['web/bundles/*/less/*.less'],
                tasks: ['css', 'command:assetic_dump']
            },
            javascript: {
                files: ['web/bundles/*/coffee/*.coffee'],
                tasks: ['javascript', 'command:assetic_dump']
            }
        },

        command : {
            assets_install: {
                cmd  : 'php app/console assets:install --symlink'
            },
            assetic_dump: {
                cmd  : 'php app/console assetic:dump'
            }
        }
    });

    // Default task(s).
    grunt.registerTask('default', ['clean', 'command:assets_install', 'symlink', 'css', 'javascript', 'javascriptProd', 'command:assetic_dump']);
    grunt.registerTask('css', ['less:discovering', 'less', 'concat:smartadmincss', 'concat:libcss', 'concat:orchestracss', 'concat:css', 'cssmin']);
    grunt.registerTask('javascript', ['coffee:discovering', 'coffee', 'concat:smartadminjs', 'concat:libjs', 'concat:orchestrajs', 'concat:js']);
    grunt.registerTask('javascriptProd', ['uglify']);
    grunt.registerTask('less:discovering', 'This is a function', function() {
        // LESS Files management
        // Source LESS files are located inside : bundles/[bundle]/less/
        // Destination CSS files are located inside : built/[bundle]/css/
        var mappingFileLess = grunt.file.expandMapping(
            ['*/less/*.less', '*/less/*/*.less'],
            'web/built/', {
                cwd: 'web/bundles/',
                rename: function(dest, matchedSrcPath, options) {
                    return dest + matchedSrcPath.replace(/less/g, 'css');
                }
            });

        grunt.util._.each(mappingFileLess, function(value) {
            // Why value.src is an array ??
            filesLess[value.dest] = value.src[0];
        });
    });
    grunt.registerTask('coffee:discovering', 'This is a function', function() {
        // COFFEE Files management
        // Source COFFEE files are located inside : bundles/[bundle]/coffee/
        // Destination JS files are located inside : built/[bundle]/js/
        var mappingFileCoffee = grunt.file.expandMapping(
            ['*/coffee/*.coffee', '*/coffee/*/*.coffee'],
            'web/built/', {
                cwd: 'web/bundles/',
                rename: function(dest, matchedSrcPath, options) {
                    return dest + matchedSrcPath.replace(/coffee/g, 'js');
                }
            });

        grunt.util._.each(mappingFileCoffee, function(value) {
            // Why value.src is an array ??
            filesCoffee[value.dest] = value.src[0];
        });
    });
};
<|endoftext|>


<commit_before>"use strict";

/**
 * Adds the `hover` event as a DOM-event to event-dom. more about DOM-events:
 * http://www.smashingmagazine.com/2013/11/12/an-introduction-to-dom-events/
 *
 * Should be called using  the provided `mergeInto`-method like this:
 *
 *
 * Copyright (c) 2014 ITSA - https://github.com/itsa
 * New BSD License - http://choosealicense.com/licenses/bsd-3-clause/
 *
 * @example
 * Event = require('event-dom/hover.js')(window);
 *
 * or
 *
 * @example
 * Event = require('event-dom')(window);
 * require('event-dom/event-hover.js')(window);
 *
 * @module event
 * @submodule event-hover
 * @class Event
 * @since 0.0.2
*/
require('dom-ext');

var NAME = '[event-valuechange]: ',
    VALUE = 'value',
    DATA_KEY = 'valueChange',
    UTILS = require('utils'),

    /**
    Interval (in milliseconds) at which to poll for changes to the value of an
    element with one or more `valuechange` subscribers when the user is likely
    to be interacting with it.

    @property POLL_INTERVAL
    @type Number
    @default 50
    @static
    **/
    POLL_INTERVAL = 50;

module.exports = function (window) {

    var Event = require('../event-dom.js')(window),
    subscriberBlur,
    subscriberFocus,
    subscriberKeypress,
    subscriberClick,

    /*
     * Checks if the HtmlElement is editable.
     *
     * @method editableNode
     * @param node {HtmlElement}
     * @private
     * @return {Boolean} whether the HtmlElement is editable.
     * @since 0.0.1
     */
    editableNode = function(node) {
        var editable;
        if (node===window.document) {
            return false;
        }
        console.log(NAME, 'editableNodes '+node.test('input, textarea, select') || ((editable=node.getAttr('contenteditable')) && (editable!=='false')));
        return node.test('input, textarea, select') || ((editable=node.getAttr('contenteditable')) && (editable!=='false'));
    },

    /*
     * Gets invokes when the HtmlElement gets focus. Initializes a `keypress` and `click`/'press' eventlisteners.
     *
     * @method startFocus
     * @param e {Object} eventobject
     * @private
     * @since 0.0.1
     */
    startFocus = function(e) {
        console.log(NAME, 'startFocus');
        var node = e.target,
            editable, valueChangeData, previousValue;

        if (!editableNode(node)) {
            return;
        }

        // first backup the current value:
        editable = ((editable=node.getAttr('contenteditable')) && (editable!=='false'));
        valueChangeData = node.getData(DATA_KEY);

        if (!valueChangeData) {
            valueChangeData = {
                editable : editable
            };
            node.setData(DATA_KEY, valueChangeData);
        }
        valueChangeData.prevVal = editable ? node.innerHTML : node[VALUE];

        // now activate keylistener: this must be an after-listener, because the key is then part of the value
        subscriberKeypress = Event.after('keypress', checkChanged);

        // now activate a mouselistener, in case of when someone right-clicks and pasts data.
        // should be after mousepress: the node has to be focussed first to start capturing
        // check all buttons: the user may have swapped functionality
        // Also, check `press` event, which is generated by HammerJS: this to support mobile:
        subscriberClick = Event.after('tap', startPolling);
    },

    /*
     * Removes the `focus` and `blur` events and ends the polling - if running. Because there are no subscribers anymore.
     *
     * @method endFocus
     * @private
     * @since 0.0.1
     */
    endFocus = function(e) {
        console.log(NAME, 'endFocus');
        subscriberKeypress && subscriberKeypress.detach();
        subscriberClick && subscriberClick.detach();
        stopPolling(e.target);
    },

    /*
     * Creates the `focus` and `blur` events. Also invokes `startFocus` to do inititalization.
     *
     * @method setupValueChange
     * @private
     * @since 0.0.2
     */
    setupValueChange = function() {
        console.log(NAME, 'setupValueChange');
        // create only after subscribing to the `hover`-event
        subscriberBlur = Event.after('blur', endFocus);
        subscriberFocus = Event.after('focus', startFocus);
        startFocus({target: window.document.activeElement});
    },

    /*
     * Starts polling in case of mouseclicks.
     *
     * @method startPolling
     * @private
     * @since 0.0.1
     */
    startPolling = function(e) {
        var node = e.target,
            valueChangeData;

        if (!editableNode(node)) {
            return;
        }
        console.log(NAME, 'startPolling');

        valueChangeData = node.getData(DATA_KEY);
        // cancel previous timer: we don't want multiple timers:
        valueChangeData.timer && valueChangeData.timer.cancel();
        // setup a new timer:
        valueChangeData.timer = UTILS.later(checkChanged.bind(null, e), POLL_INTERVAL, true);
    },

    /*
     * Stops polling on the specific HtmlElement
     *
     * @method stopPolling
     * @param node {HtmlElement} the HtmlElement that should stop polling.
     * @private
     * @since 0.0.1
     */
    stopPolling = function(node) {
        console.log(NAME, 'stopPolling');
        var valueChangeData = node.getData(DATA_KEY);
        valueChangeData && valueChangeData.timer && valueChangeData.timer.cancel();
    },

    /*
     * Checks e.target if its value has changed. If so, it will fire the `valuechange`-event.
     *
     * @method checkChanged
     * @param e {Object} eventobject
     * @private
     * @since 0.0.1
     */
    checkChanged = function(e) {
        console.log(NAME, 'checkChanged');
        var node = e.target;
        // because of delegating all matched HtmlElements come along: only check the node that has focus:
        if (window.document.activeElement!==node) {
            return;
        }
        var prevData = node.getData(DATA_KEY),
            editable = ((editable=node.getAttr('contenteditable')) && (editable!=='false')),
            currentData = editable ? node.innerHTML : node[VALUE];
        if (currentData!==prevData.prevVal) {
            console.log(NAME, 'checkChanged --> value has been changed');
            window.document._emitVC(node, currentData);
            prevData.prevVal = currentData;
            stopPolling(node);
        }
    },

    /*
     * Removes the `focus` and `blur` events and ends the polling - if running. Because there are no subscribers anymore.
     *
     * @method teardownValueChange
     * @private
     * @since 0.0.1
     */
    teardownValueChange = function() {
        // check if there aren't any subscribers anymore.
        // in that case, we detach the `mouseover` lister because we don't want to
        // loose performance.
        if (!Event._subs['UI:valuechange']) {
            console.log(NAME, 'teardownValueChange: stop setting up blur and focus-event');
            subscriberBlur.detach();
            subscriberFocus.detach();
            // also stop any possible action/listeners to a current element:
            endFocus({target: window.document.activeElement});
            // reinit notifier, because it is a one-time notifier:
            Event.notify('UI:valuechange', setupValueChange, Event, true);
        }
    };

    Event.notify('UI:valuechange', setupValueChange, Event, true);
    Event.notifyDetach('UI:valuechange', teardownValueChange, Event);

    /*
     * Emits the `valuechange`-event on the specified node. Also adds e.value with the new value.
     *
     * @method _emitVC
     * @param node {HtmlElement} the HtmlElement that fires the event
     * @param value {String} the new value
     * @private
     * @since 0.0.1
     */
    window.document._emitVC = function(node, value) {
        console.log(NAME, 'document._emitVC');
        var e = {
            value: value,
            target: node,
            currentTarget: window.document,
            sourceTarget: node
        };
        Event.emit(node, 'UI:valuechange', e);
    };

    return Event;
};
<commit_msg>allways use polling<commit_after>"use strict";

/**
 * Adds the `hover` event as a DOM-event to event-dom. more about DOM-events:
 * http://www.smashingmagazine.com/2013/11/12/an-introduction-to-dom-events/
 *
 * Should be called using  the provided `mergeInto`-method like this:
 *
 *
 * Copyright (c) 2014 ITSA - https://github.com/itsa
 * New BSD License - http://choosealicense.com/licenses/bsd-3-clause/
 *
 * @example
 * Event = require('event-dom/hover.js')(window);
 *
 * or
 *
 * @example
 * Event = require('event-dom')(window);
 * require('event-dom/event-hover.js')(window);
 *
 * @module event
 * @submodule event-hover
 * @class Event
 * @since 0.0.2
*/
require('dom-ext');

var NAME = '[event-valuechange]: ',
    VALUE = 'value',
    DATA_KEY = 'valueChange',
    UTILS = require('utils'),

    /**
    Interval (in milliseconds) at which to poll for changes to the value of an
    element with one or more `valuechange` subscribers when the user is likely
    to be interacting with it.

    @property POLL_INTERVAL
    @type Number
    @default 50
    @static
    **/
    POLL_INTERVAL = 50;

module.exports = function (window) {

    var Event = require('../event-dom.js')(window),
    subscriberBlur,
    subscriberFocus,

    /*
     * Checks if the HtmlElement is editable.
     *
     * @method editableNode
     * @param node {HtmlElement}
     * @private
     * @return {Boolean} whether the HtmlElement is editable.
     * @since 0.0.1
     */
    editableNode = function(node) {
        var editable;
        if (node===window.document) {
            return false;
        }
        console.log(NAME, 'editableNodes '+node.test('input, textarea, select') || ((editable=node.getAttr('contenteditable')) && (editable!=='false')));
        return node.test('input, textarea, select') || ((editable=node.getAttr('contenteditable')) && (editable!=='false'));
    },

    /*
     * Gets invokes when the HtmlElement gets focus. Initializes a `keypress` and `click`/'press' eventlisteners.
     *
     * @method startFocus
     * @param e {Object} eventobject
     * @private
     * @since 0.0.1
     */
    startFocus = function(e) {
        console.log(NAME, 'startFocus');
        var node = e.target,
            editable, valueChangeData, previousValue;

        if (!editableNode(node)) {
            return;
        }

        // first backup the current value:
        editable = ((editable=node.getAttr('contenteditable')) && (editable!=='false'));
        valueChangeData = node.getData(DATA_KEY);

        if (!valueChangeData) {
            valueChangeData = {
                editable : editable
            };
            node.setData(DATA_KEY, valueChangeData);
        }
        valueChangeData.prevVal = editable ? node.innerHTML : node[VALUE];
        startPolling(e);
    },

    /*
     * Removes the `focus` and `blur` events and ends the polling - if running. Because there are no subscribers anymore.
     *
     * @method endFocus
     * @private
     * @since 0.0.1
     */
    endFocus = function(e) {
        console.log(NAME, 'endFocus');
        stopPolling(e.target);
    },

    /*
     * Creates the `focus` and `blur` events. Also invokes `startFocus` to do inititalization.
     *
     * @method setupValueChange
     * @private
     * @since 0.0.2
     */
    setupValueChange = function() {
        console.log(NAME, 'setupValueChange');
        // create only after subscribing to the `hover`-event
        subscriberBlur = Event.after('blur', endFocus);
        subscriberFocus = Event.after('focus', startFocus);
        startFocus({target: window.document.activeElement});
    },

    /*
     * Starts polling in case of mouseclicks.
     *
     * @method startPolling
     * @private
     * @since 0.0.1
     */
    startPolling = function(e) {
        var node = e.target,
            valueChangeData;

        if (!editableNode(node)) {
            return;
        }
        console.log(NAME, 'startPolling');

        valueChangeData = node.getData(DATA_KEY);
        // cancel previous timer: we don't want multiple timers:
        valueChangeData.timer && valueChangeData.timer.cancel();
        // setup a new timer:
        valueChangeData.timer = UTILS.later(checkChanged.bind(null, e), POLL_INTERVAL, true);
    },

    /*
     * Stops polling on the specific HtmlElement
     *
     * @method stopPolling
     * @param node {HtmlElement} the HtmlElement that should stop polling.
     * @private
     * @since 0.0.1
     */
    stopPolling = function(node) {
        console.log(NAME, 'stopPolling');
        var valueChangeData = node.getData(DATA_KEY);
        valueChangeData && valueChangeData.timer && valueChangeData.timer.cancel();
    },

    /*
     * Checks e.target if its value has changed. If so, it will fire the `valuechange`-event.
     *
     * @method checkChanged
     * @param e {Object} eventobject
     * @private
     * @since 0.0.1
     */
    checkChanged = function(e) {
        console.log(NAME, 'checkChanged');
        var node = e.target;
        // because of delegating all matched HtmlElements come along: only check the node that has focus:
        if (window.document.activeElement!==node) {
            return;
        }
        var prevData = node.getData(DATA_KEY),
            editable = ((editable=node.getAttr('contenteditable')) && (editable!=='false')),
            currentData = editable ? node.innerHTML : node[VALUE];
        if (currentData!==prevData.prevVal) {
            console.log(NAME, 'checkChanged --> value has been changed');
            window.document._emitVC(node, currentData);
            prevData.prevVal = currentData;
        }
    },

    /*
     * Removes the `focus` and `blur` events and ends the polling - if running. Because there are no subscribers anymore.
     *
     * @method teardownValueChange
     * @private
     * @since 0.0.1
     */
    teardownValueChange = function() {
        // check if there aren't any subscribers anymore.
        // in that case, we detach the `mouseover` lister because we don't want to
        // loose performance.
        if (!Event._subs['UI:valuechange']) {
            console.log(NAME, 'teardownValueChange: stop setting up blur and focus-event');
            subscriberBlur.detach();
            subscriberFocus.detach();
            // also stop any possible action/listeners to a current element:
            endFocus({target: window.document.activeElement});
            // reinit notifier, because it is a one-time notifier:
            Event.notify('UI:valuechange', setupValueChange, Event, true);
        }
    };

    Event.notify('UI:valuechange', setupValueChange, Event, true);
    Event.notifyDetach('UI:valuechange', teardownValueChange, Event);

    /*
     * Emits the `valuechange`-event on the specified node. Also adds e.value with the new value.
     *
     * @method _emitVC
     * @param node {HtmlElement} the HtmlElement that fires the event
     * @param value {String} the new value
     * @private
     * @since 0.0.1
     */
    window.document._emitVC = function(node, value) {
        console.log(NAME, 'document._emitVC');
        var e = {
            value: value,
            target: node,
            currentTarget: window.document,
            sourceTarget: node
        };
        Event.emit(node, 'UI:valuechange', e);
    };

    return Event;
};
<|endoftext|>


<commit_before>/*jshint expr:true */
'use strict';

var PouchDB = require('pouchdb');

//
// your plugin goes here
//
var plugin = require('../');
PouchDB.plugin(plugin);

var chai = require('chai');
chai.use(require("chai-as-promised"));

//
// more variables you might want
//
var should = chai.should(); // var should = chai.should();
var Promise = require('bluebird'); // var Promise = require('bluebird');

var dbs;
if (process.browser) {
  dbs = 'testdb' + Math.random() +
    ',http://localhost:5984/testdb' + Math.round(Math.random() * 100000);
} else {
  dbs = process.env.TEST_DB;
}

dbs.split(',').forEach(function (db) {
  var dbType = /^http/.test(db) ? 'http' : 'local';
  tests(db, dbType);
});

function chain(promiseFactories) {
  var promise = Promise.resolve();
  promiseFactories.forEach(function (promiseFactory) {
    promise = promise.then(promiseFactory);
  });
  return promise;
}

function tests(dbName, dbType) {

  var db;

  beforeEach(function () {
    db = new PouchDB(dbName);
    return db;
  });
  afterEach(function () {
    return PouchDB.destroy(dbName);
  });
  describe(dbType + ': main test suite', function () {
    this.timeout(30000);

    function blobEquals(blob, base64) {
      if (typeof process === 'undefined' || !process.browser) {
        should.equal(blob.toString('base64'), base64);
      } else {
        return new Promise(function (resolve) {
          var reader = new FileReader();
          reader.onloadend = function () {
            var binary = "";
            var bytes = new Uint8Array(this.result || '');
            var length = bytes.byteLength;

            for (var i = 0; i < length; i++) {
              binary += String.fromCharCode(bytes[i]);
            }
            resolve(btoa(binary));
          };
          reader.readAsArrayBuffer(blob);
        });
      }

    }

    it('should store an attachment', function () {
      db.initLru();

      return db.lru.put('mykey', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('mykey');
      }).then(function (blob) {
        return blobEquals(blob, 'Zm9v');
      });
    });

    it('should store an attachment twice', function () {
      db.initLru();

      return db.lru.put('mykey', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('mykey');
      }).then(function (blob) {
        return blobEquals(blob, 'Zm9v');
      }).then(function () {
        return db.lru.put('mykey', 'Zm9v', 'text/plain');
      });
    });

    it('should throw 404s', function () {
      db.initLru();

      return db.lru.get('mykey').then(function () {
        throw new Error('should not be here');
      }, function (err) {
        err.status.should.equal(404);
      });
    });

    it('works with blobs', function () {
      db.initLru();
      return db.lru.put('mykey', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('mykey');
      }).then(function (blob) {
        return db.lru.put('otherkey', blob, 'text/plain');
      });
    });

    it('throws an err if you forget the type', function () {
      db.initLru();
      return db.lru.put('mykey', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('mykey');
      }).then(function (blob) {
        return db.lru.put('otherkey', blob).then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      });
    });

    it('deletes the least-recently used things', function () {
      // the contents are "foo" and "bar", so let's try going over 5
      db.initLru(5);
      return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('foo');
      }).then(function (blob) {
        return blobEquals(blob, 'Zm9v');
      }).then(function () {
        return db.lru.put('bar', 'YmFy', 'text/plain');
      }).then(function () {
        return db.lru.get('foo').then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('bar');
      }).then(function (blob) {
        return blobEquals(blob, 'YmFy');
      });
    });

    it('doesn\'t delete if unnecessary', function () {
      // the contents are "foo" and "bar", i.e. each length 3

      var sizes = [0, 6, 10, 100000000];

      return chain(sizes.map(function (size) {
        return function () {
          db.initLru(size);
          return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
            return db.lru.get('foo');
          }).then(function (blob) {
            return blobEquals(blob, 'Zm9v');
          }).then(function () {
            return db.lru.put('bar', 'YmFy', 'text/plain');
          }).then(function () {
            return db.lru.get('foo');
          }).then(function (blob) {
            return blobEquals(blob, 'Zm9v');
          }).then(function () {
            return db.lru.get('bar');
          }).then(function (blob) {
            return blobEquals(blob, 'YmFy');
          });
        };
      }));

    });

    it('deletes multiple least-recently used things', function () {
      // the contents are "foo" and "bar", so let's try going over 8
      db.initLru(8);
      return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
        return db.lru.put('bar', 'YmFy', 'text/plain');
      }).then(function () {
        return db.lru.put('foobar', 'Zm9vYmFy', 'text/plain');
      }).then(function () {
        return db.lru.get('foo').then(function () {
          throw new Error('should not be here: foo');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('bar').then(function () {
          throw new Error('should not be here: bar');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('foobar');
      }).then(function (blob) {
        return blobEquals(blob, 'Zm9vYmFy');
      });
    });

    it('doesnt even store one thing if too large', function () {
      // the contents are "foo" and "bar", so let's try going over 8
      db.initLru(1);
      return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('foo').then(function () {
          throw new Error('should not be here: foo');
        }, function (err) {
          should.exist(err);
        });
      });
    });

    it('updates what\'s recently used', function () {
      db.initLru(10);
      return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
        return db.lru.put('bar', 'YmFy', 'text/plain');
      }).then(function () {
        return db.lru.get('foo'); // updates foo
      }).then(function () {
        return db.lru.put('foobar', 'Zm9vYmFy', 'text/plain');
      }).then(function () {
        return db.lru.get('foo');
      }).then(function () {
        return db.lru.get('foobar');
      }).then(function () {
        return db.lru.get('bar').then(function () {
          throw new Error('should not be here: foo');
        }, function (err) {
          should.exist(err);
        });
      });
    });

    it('can put after deleting', function () {
      db.initLru(5);
      return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('foo');
      }).then(function () {
        return db.lru.put('bar', 'YmFy', 'text/plain');
      }).then(function () {
        return db.lru.get('foo').then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('bar');
      }).then(function () {
        return db.lru.put('foo', 'Zm9v', '/text/plain');
      }).then(function () {
        // now the tables have turned
        return db.lru.get('foo');
      }).then(function () {
        return db.lru.get('bar').then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      });
    });

    // 68 in length
    var transparent1x1Png =
      'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGP6zwAAAgcBApocMXEA' +
      'AAAASUVORK5CYII=';
    // 68 in length
    var black1x1Png =
      'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAA' +
      'AABJRU5ErkJggg==';

    it('handles dups', function () {
      db.initLru(160);
      return db.lru.put('foo.png', transparent1x1Png, 'image/png').then(function () {
        return db.lru.put('bar.png', transparent1x1Png, 'image/png');
      }).then(function () {
        return db.lru.put('baz.png', black1x1Png, 'image/png');
      }).then(function () {
        return db.lru.get('foo.png');
      }).then(function () {
        return db.lru.get('bar.png');
      }).then(function () {
        return db.lru.get('baz.png');
      }).then(function () {
        return db.lru.info();
      }).then(function (info) {
        Object.keys(info.items).sort().should.deep.equal(
          ['bar.png', 'baz.png', 'foo.png']);
        info.numUniqueItems.should.equal(2);
        info.numEvicted.should.equal(0);
        [135, 149].indexOf(info.totalLength).should.be.above(-1,
            'expected either 135 or 149, and it is: ' + info.totalLength);
      });
    });

    it('counts evicted', function () {
      db.initLru(80);
      return db.lru.put('foo.png', transparent1x1Png, 'image/png').then(function () {
        return db.lru.put('bar.png', transparent1x1Png, 'image/png');
      }).then(function () {
        return db.lru.put('baz.png', black1x1Png, 'image/png');
      }).then(function () {
        return db.lru.get('foo.png').then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('bar.png').then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('baz.png');
      }).then(function () {
        return db.lru.info();
      }).then(function (info) {
        Object.keys(info.items).sort().should.deep.equal(
          ['baz.png']);
        info.numUniqueItems.should.equal(1);
        info.numEvicted.should.equal(1);
        [67, 73].indexOf(info.totalLength).should.be.above(-1,
            'expected either 67 or 73, and it is: ' + info.totalLength);
      });
    });

    function compatBtoa(str) {
      if (typeof process === 'undefined' || process.browser) {
        return btoa(str);
      } else {
        return new Buffer(str).toString('base64');
      }
    }

    it('issue #1, concurrent puts cause 409s', function () {
      this.timeout(60000);
      db.initLru(0);
      var tasks = [];
      for (var i = 0; i < 20; i++) {
        tasks.push(i);
      }
      return Promise.all(tasks.map(function (i) {
        var key = 'key_' + i;
        var value = compatBtoa(i.toString());
        return db.lru.put(key, value, 'text/plain').then(function () {
          return Promise.all([
            db.lru.put(key, value, 'text/plain'),
            db.lru.get(key),
            db.lru.put(key, value, 'text/plain'),
            db.lru.get(key),
            db.lru.put(key, value, 'text/plain'),
            db.lru.get(key),
            db.lru.put(key, value, 'text/plain')
          ]);
        });
      })).catch(function (err) {
        throw err;
      });
    });
  });
}
<commit_msg>increase test timeout<commit_after>/*jshint expr:true */
'use strict';

var PouchDB = require('pouchdb');

//
// your plugin goes here
//
var plugin = require('../');
PouchDB.plugin(plugin);

var chai = require('chai');
chai.use(require("chai-as-promised"));

//
// more variables you might want
//
var should = chai.should(); // var should = chai.should();
var Promise = require('bluebird'); // var Promise = require('bluebird');

var dbs;
if (process.browser) {
  dbs = 'testdb' + Math.random() +
    ',http://localhost:5984/testdb' + Math.round(Math.random() * 100000);
} else {
  dbs = process.env.TEST_DB;
}

dbs.split(',').forEach(function (db) {
  var dbType = /^http/.test(db) ? 'http' : 'local';
  tests(db, dbType);
});

function chain(promiseFactories) {
  var promise = Promise.resolve();
  promiseFactories.forEach(function (promiseFactory) {
    promise = promise.then(promiseFactory);
  });
  return promise;
}

function tests(dbName, dbType) {

  var db;

  beforeEach(function () {
    this.timeout(30000);
    db = new PouchDB(dbName);
    return db;
  });
  afterEach(function () {
    this.timeout(30000);
    return PouchDB.destroy(dbName);
  });
  describe(dbType + ': main test suite', function () {
    this.timeout(30000);

    function blobEquals(blob, base64) {
      if (typeof process === 'undefined' || !process.browser) {
        should.equal(blob.toString('base64'), base64);
      } else {
        return new Promise(function (resolve) {
          var reader = new FileReader();
          reader.onloadend = function () {
            var binary = "";
            var bytes = new Uint8Array(this.result || '');
            var length = bytes.byteLength;

            for (var i = 0; i < length; i++) {
              binary += String.fromCharCode(bytes[i]);
            }
            resolve(btoa(binary));
          };
          reader.readAsArrayBuffer(blob);
        });
      }

    }

    it('should store an attachment', function () {
      db.initLru();

      return db.lru.put('mykey', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('mykey');
      }).then(function (blob) {
        return blobEquals(blob, 'Zm9v');
      });
    });

    it('should store an attachment twice', function () {
      db.initLru();

      return db.lru.put('mykey', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('mykey');
      }).then(function (blob) {
        return blobEquals(blob, 'Zm9v');
      }).then(function () {
        return db.lru.put('mykey', 'Zm9v', 'text/plain');
      });
    });

    it('should throw 404s', function () {
      db.initLru();

      return db.lru.get('mykey').then(function () {
        throw new Error('should not be here');
      }, function (err) {
        err.status.should.equal(404);
      });
    });

    it('works with blobs', function () {
      db.initLru();
      return db.lru.put('mykey', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('mykey');
      }).then(function (blob) {
        return db.lru.put('otherkey', blob, 'text/plain');
      });
    });

    it('throws an err if you forget the type', function () {
      db.initLru();
      return db.lru.put('mykey', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('mykey');
      }).then(function (blob) {
        return db.lru.put('otherkey', blob).then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      });
    });

    it('deletes the least-recently used things', function () {
      // the contents are "foo" and "bar", so let's try going over 5
      db.initLru(5);
      return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('foo');
      }).then(function (blob) {
        return blobEquals(blob, 'Zm9v');
      }).then(function () {
        return db.lru.put('bar', 'YmFy', 'text/plain');
      }).then(function () {
        return db.lru.get('foo').then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('bar');
      }).then(function (blob) {
        return blobEquals(blob, 'YmFy');
      });
    });

    it('doesn\'t delete if unnecessary', function () {
      // the contents are "foo" and "bar", i.e. each length 3

      var sizes = [0, 6, 10, 100000000];

      return chain(sizes.map(function (size) {
        return function () {
          db.initLru(size);
          return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
            return db.lru.get('foo');
          }).then(function (blob) {
            return blobEquals(blob, 'Zm9v');
          }).then(function () {
            return db.lru.put('bar', 'YmFy', 'text/plain');
          }).then(function () {
            return db.lru.get('foo');
          }).then(function (blob) {
            return blobEquals(blob, 'Zm9v');
          }).then(function () {
            return db.lru.get('bar');
          }).then(function (blob) {
            return blobEquals(blob, 'YmFy');
          });
        };
      }));

    });

    it('deletes multiple least-recently used things', function () {
      // the contents are "foo" and "bar", so let's try going over 8
      db.initLru(8);
      return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
        return db.lru.put('bar', 'YmFy', 'text/plain');
      }).then(function () {
        return db.lru.put('foobar', 'Zm9vYmFy', 'text/plain');
      }).then(function () {
        return db.lru.get('foo').then(function () {
          throw new Error('should not be here: foo');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('bar').then(function () {
          throw new Error('should not be here: bar');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('foobar');
      }).then(function (blob) {
        return blobEquals(blob, 'Zm9vYmFy');
      });
    });

    it('doesnt even store one thing if too large', function () {
      // the contents are "foo" and "bar", so let's try going over 8
      db.initLru(1);
      return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('foo').then(function () {
          throw new Error('should not be here: foo');
        }, function (err) {
          should.exist(err);
        });
      });
    });

    it('updates what\'s recently used', function () {
      db.initLru(10);
      return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
        return db.lru.put('bar', 'YmFy', 'text/plain');
      }).then(function () {
        return db.lru.get('foo'); // updates foo
      }).then(function () {
        return db.lru.put('foobar', 'Zm9vYmFy', 'text/plain');
      }).then(function () {
        return db.lru.get('foo');
      }).then(function () {
        return db.lru.get('foobar');
      }).then(function () {
        return db.lru.get('bar').then(function () {
          throw new Error('should not be here: foo');
        }, function (err) {
          should.exist(err);
        });
      });
    });

    it('can put after deleting', function () {
      db.initLru(5);
      return db.lru.put('foo', 'Zm9v', 'text/plain').then(function () {
        return db.lru.get('foo');
      }).then(function () {
        return db.lru.put('bar', 'YmFy', 'text/plain');
      }).then(function () {
        return db.lru.get('foo').then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('bar');
      }).then(function () {
        return db.lru.put('foo', 'Zm9v', '/text/plain');
      }).then(function () {
        // now the tables have turned
        return db.lru.get('foo');
      }).then(function () {
        return db.lru.get('bar').then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      });
    });

    // 68 in length
    var transparent1x1Png =
      'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGP6zwAAAgcBApocMXEA' +
      'AAAASUVORK5CYII=';
    // 68 in length
    var black1x1Png =
      'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVR4nGNiAAAABgADNjd8qAAA' +
      'AABJRU5ErkJggg==';

    it('handles dups', function () {
      db.initLru(160);
      return db.lru.put('foo.png', transparent1x1Png, 'image/png').then(function () {
        return db.lru.put('bar.png', transparent1x1Png, 'image/png');
      }).then(function () {
        return db.lru.put('baz.png', black1x1Png, 'image/png');
      }).then(function () {
        return db.lru.get('foo.png');
      }).then(function () {
        return db.lru.get('bar.png');
      }).then(function () {
        return db.lru.get('baz.png');
      }).then(function () {
        return db.lru.info();
      }).then(function (info) {
        Object.keys(info.items).sort().should.deep.equal(
          ['bar.png', 'baz.png', 'foo.png']);
        info.numUniqueItems.should.equal(2);
        info.numEvicted.should.equal(0);
        [135, 149].indexOf(info.totalLength).should.be.above(-1,
            'expected either 135 or 149, and it is: ' + info.totalLength);
      });
    });

    it('counts evicted', function () {
      db.initLru(80);
      return db.lru.put('foo.png', transparent1x1Png, 'image/png').then(function () {
        return db.lru.put('bar.png', transparent1x1Png, 'image/png');
      }).then(function () {
        return db.lru.put('baz.png', black1x1Png, 'image/png');
      }).then(function () {
        return db.lru.get('foo.png').then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('bar.png').then(function () {
          throw new Error('should not be here');
        }, function (err) {
          should.exist(err);
        });
      }).then(function () {
        return db.lru.get('baz.png');
      }).then(function () {
        return db.lru.info();
      }).then(function (info) {
        Object.keys(info.items).sort().should.deep.equal(
          ['baz.png']);
        info.numUniqueItems.should.equal(1);
        info.numEvicted.should.equal(1);
        [67, 73].indexOf(info.totalLength).should.be.above(-1,
            'expected either 67 or 73, and it is: ' + info.totalLength);
      });
    });

    function compatBtoa(str) {
      if (typeof process === 'undefined' || process.browser) {
        return btoa(str);
      } else {
        return new Buffer(str).toString('base64');
      }
    }

    it('issue #1, concurrent puts cause 409s', function () {
      this.timeout(60000);
      db.initLru(0);
      var tasks = [];
      for (var i = 0; i < 20; i++) {
        tasks.push(i);
      }
      return Promise.all(tasks.map(function (i) {
        var key = 'key_' + i;
        var value = compatBtoa(i.toString());
        return db.lru.put(key, value, 'text/plain').then(function () {
          return Promise.all([
            db.lru.put(key, value, 'text/plain'),
            db.lru.get(key),
            db.lru.put(key, value, 'text/plain'),
            db.lru.get(key),
            db.lru.put(key, value, 'text/plain'),
            db.lru.get(key),
            db.lru.put(key, value, 'text/plain')
          ]);
        });
      })).catch(function (err) {
        throw err;
      });
    });
  });
}
<|endoftext|>


<commit_before>/* public functions
************************************/
Elba.prototype = {

	defaults : {
		selector : '.elba',
		separator : '|',
		breakpoints : false,
		successClass : 'elba-loaded',
		errorClass : 'elba-error',
		src : 'data-src',
		error : false,
		success : false,
		duration : 1000,
		delta : function(progress){
			return power(progress, 2);
		},
		delay : 10,
		transitionEase : 'ease-in-out'
	},
	swipe : function(direction){
		var self = this;

		if(direction === 'right'){
			goTo(self.el, 'right');
		}else{
			goTo(self.el, 'left');
		}
	}
};	<commit_msg>Changing animation method<commit_after>/* public functions
************************************/
Elba.prototype = {

	defaults : {
		selector : '.elba',
		separator : '|',
		breakpoints : false,
		successClass : 'elba-loaded',
		errorClass : 'elba-error',
		src : 'data-src',
		error : false,
		success : false,
		duration : 1000,
		delta : function(progress){
			return power(progress, 2);
		},
		delay : 5,
		transitionEase : 'ease-in-out'
	},
	swipe : function(direction){
		var self = this;

		if(direction === 'right'){
			goTo(self.el, 'right');
		}else{
			goTo(self.el, 'left');
		}
	}
};	<|endoftext|>


<commit_before>var events = require('events'),
    util = require('util'),
    validator = require('revalidator'),
    common = require('./common'),
    definers  = require('./definers')
    resourceful = require('../resourceful');;

//
// CRUD
//
var Resource = exports.Resource = function () {
  Object.defineProperty(this, 'isNewRecord', {
      value: true, writable: true
  });
};

//
// Hooks
//
Resource.after = function (event, callback) {
  this.hook(event, 'after', callback);
};
Resource.before = function (event, callback) {
  this.hook(event, 'before', callback);
};
Resource.hook = function (event, timing, callback) {
  this.hooks[timing][event] = this.hooks[timing][event] || [];
  this.hooks[timing][event].push(callback);
};
Resource.runBeforeHooks = function (method, obj, callback, finish) {
  if (method in this.hooks.before) {
    (function loop(hooks) {
      var hook = hooks.shift();

      if (hook) {
        hook(obj, function (e, obj) {
          if (e || obj) { callback(e, obj) }
          else          { loop(hooks) }
        });
      } else {
        finish();
      }
    })(this.hooks.before[method].slice(0));
  } else { finish() }
};
Resource.runAfterHooks = function (method, e, obj, finish) {
  if (method in this.hooks.before) {
    (function loop(hooks) {
      var hook = hooks.shift();

      if (hook) {
        hook(e, obj, function (e, obj) {
          if (e) { finish(e, obj) }
          else   { loop(hooks) }
        });
      } else {
        finish();
      }
    })(this.hooks.after[method].slice(0));
  } else { finish() }
};

//
// Raises the init event. Called from resourceful.define
//
Resource.init = function () {
  this.emit('init', this);
};

//
// Registers the current instance's resource with resourceful
//
Resource.register = function () {
  return resourceful.register(this.resource, this);
};

//
// Unregisters the current instance's resource from resourceful
//
Resource.unregister = function () {
  return resourceful.unregister(this.resource);
};

Resource._request = function (/* method, [key, obj], callback */) {
  var args     = Array.prototype.slice.call(arguments),
      that     = this,
      callback = args.pop(),
      method   = args.shift(),
      key      = args.shift(),
      obj      = args.shift();

  key && args.push(key);
  obj && args.push(obj.properties ? obj.properties : obj);

  this.runBeforeHooks(method, obj, callback, function () {
    args.push(function (e, result) {
      var Factory;

      if (e) {
        if (e.status >= 500) {
          throw new(Error)(e);
        } else {
          that.runAfterHooks(method, e, obj, function () {
            that.emit("error", e, obj);
            callback(e);
          });
        }
      } else {
        if (Array.isArray(result)) {
          result = result.map(function (r) {
            return resourceful.instantiate.call(that, r);
          });
        } else {
          if (method === 'destroy') {
            that.connection.cache.clear(key);
          } else {
            if (result.rev) {
              // Set the revision if available, so it can be saved
              // to the cache. If we're saving a new object,
              // '_rev' won't be a member of 'resource._properties'
              // so we need to set it here so resource.toJSON() includes it.
              if (obj instanceof resourceful.Resource && !obj._rev) {
                resourceful.defineProperty(obj, '_rev');
              }
              obj._rev = result.rev;
            }
            result = resourceful.instantiate.call(that, method === 'get' ? result : obj);

            if (method === 'update') {
              // TODO: Not necessary for identity map
              that.connection.cache.update(key, obj);
            } else {
              // TODO: We only need to do this if the key doesn't exist
              that.connection.cache.put(key, result);
            }
          }
        }
        that.runAfterHooks(method, null, obj, function (e, res) {
          if (e) { that.emit('error', e) }
          else   { that.emit(method, res || result) }
          callback(e || null, result);
        });
      }
    });
    that.connection[method].apply(that.connection, args);
  });
};

Resource.get = function (id, callback) {
  return id
    ? this._request('get', id, callback)
    : callback(new Error('key is undefined'));
};

Resource.create = function (attrs, callback) {
  if (this._timestamps) {
    attrs.ctime = attrs.mtime = Date.now()
  }

  // Before we create a new resource, perform a validation based on its schema
  var validate = validator.validate(attrs, {
    properties: this.schema.properties || {}
  });

  if (!validate.valid) {
    return callback(validate.errors);
  }

  var instance = new(this)(attrs);
  instance.save(function (e, res) {
    if (res) {
      instance._id  = instance._id  || res.id;
      instance._rev = instance._rev || res.rev;
    }

    callback(e, instance);
  });
};

Resource.save = function (obj, callback) {
  // Before we save a resource,  perform a validation based on its schema
  var validate = validator.validate(obj, {
    properties: this.schema.properties || {}
  });

  if (!validate.valid) {
    return callback(validate.errors);
  }

  if (this._timestamps) {
      obj.mtime = Date.now();
      if (obj.isNewRecord) { obj.ctime = obj.mtime }
  }

  return this._request("save", obj.key, obj, callback);
};

Resource.destroy = function (key, callback) {
  return this._request("destroy", key, callback);
};

Resource.update = function (key, obj, callback) {
  if (this._timestamps) { obj.mtime = Date.now() }
  return this._request("update", key, obj, callback);
};

Resource.all = function (callback) {
  return this._request("all", callback);
};

Resource.view = function (path, params, callback) {
  return this._request("view", path, params, callback);
};

Resource.filter = function (name, options, filter) {
  return this._request("filter",
                       name,
                       { options: options, filter: filter, resource: this },
                       function () {});
};

Resource.find = function (conditions, callback) {
  if (typeof(conditions) !== "object") {
      throw new(TypeError)("`find` takes an object as first argument.");
  }
  return this._request("find", conditions, callback);
};

Resource.use = function () {
  return resourceful.use.apply(this, arguments);
};

Resource.connect = function () {
  return resourceful.connect.apply(this, arguments);
};

// Define getter / setter for connection property
Resource.__defineGetter__('connection', function () {
  return this._connection || resourceful.connection;
});
Resource.__defineSetter__('connection', function (val) {
  return this._connection = val;
});

// Define getter / setter for engine property
Resource.__defineGetter__('engine', function () {
  return this._engine || resourceful.engine;
});
Resource.__defineSetter__('engine', function (val) {
  return this._engine = val;
});

// Define getter / setter for resource property
Resource.__defineGetter__('resource', function () {
  return this._resource;
});
Resource.__defineSetter__('resource', function (name) {
  return this._resource = name;
});

// Define getter for properties, wraps this resources schema properties
Resource.__defineGetter__('properties', function () {
  return this.schema.properties;
});

// Define getter / setter for key property. The key property is required by CouchDB
Resource.__defineSetter__('key', function (val) { return this._key = val });
Resource.__defineGetter__('key', function ()    { return this._key });

Resource.__defineGetter__('children', function (name) {
  return this._children.map(function (c) { return resourceful.resources[c] });
});
Resource.__defineGetter__('parents', function (name) {
  return this._parents.map(function (c) { return resourceful.resources[c] });
});

//
// many-to-many
//
// user.groups = [1,2,3,4,5]
//
// new(User).groups() // -> bulk GET on user.groups property
//                    // OR linked documents view
//                    // OR cache
//                    // - Define Users.byGroup(group_id)
//
// new(Group).users() // -> Users.byGroup(this._id) // view
//
// group = {};
//
// User.child('group')
// Group.child('user');
//

//
// Factory method for defining basic behaviour
//
function relationship(factory, type, r, optons) {
  var engine = factory.engine,
      rfactory,     // Resource factory/constructor
      rstring,      // Resource string
      rstringp,     // Resource pluralized string
      rstringc;     // Resource capitalized string

  if (typeof(r) === 'string') {
    rstring  = r;
    rfactory = resourceful.resources[resourceful.capitalize(r)];
  } else if (typeof(r) === 'function') {
    rstringc = r.resource;
    rstring = rstringc.toLowerCase();
    rfactory = r;
  } else {
    throw new(TypeError)("argument must be a string or constructor");
  }
  rstringp = resourceful.pluralize(rstring);
  rstringc = rstringc || resourceful.capitalize(rstring);

  if (factory._children.indexOf(rstringc) !== -1) { return }
  if (rfactory === undefined) throw new(Error)("unknown resource " + rstring);

  if (type == 'child') {
    factory._children.push(rstringc);
    factory.property(rstring + '_ids', Array, { default: [] });
    //
    // Parent.children(id, callback)
    //
    if (engine._children) {
      engine._children.call(this, factory, rstringp, rfactory);
    } else {
      factory[rstringp] = function (id, callback) {
        return rfactory['by' + factory.resource](id, callback);
      };
    }
    //
    // parent.children(callback)
    //
    factory.prototype[rstringp] = function (callback) {
      return this.constructor[rstringp](this._id, callback);
    };

    rfactory.parent(factory);
  } else {
    factory._parents.push(rstringc);
    //
    // Child.byParent(id, callback)
    //
    if (engine._byParent) {
      engine._byParent.call(engine, factory, rstringc, rfactory);
    } else {
      factory['by' + rstringc] = engine._byParent || function (id, callback) {
        var filter = {};
        filter[rstring + '_id'] = id;

        factory.find(filter, callback);
      };
    }

    //
    // child.parent(callback)
    //
    factory.prototype[rstring] = function (callback) {
      return rfactory.get(this[rstring_id], callback);
    };
    factory.property(rstring + '_id', String, { default: null });

    rfactory.child(factory);
  }
};

//
// Entity relationships
//
Resource.child = function (resource, options) {
  relationship(this, 'child', resource, options);
};
Resource.parent = function (resource, options) {
  relationship(this, 'parent', resource, options);
};

Resource.property = function (name, typeOrSchema, schema) {
  var definer = {};
  var type = (function () {
    switch (typeof(typeOrSchema)) {
      case "string":    return typeOrSchema;
      case "function":  return typeOrSchema.name.toLowerCase();
      case "object":    schema = typeOrSchema;
      case "undefined": return "string";
      default:          throw new(Error)("Argument Error");
    }
  })();

  schema = schema || {};
  schema.type = schema.type || type;

  this.schema.properties[name] = definer.property = schema;
  definer.name = name;

  resourceful.mixin(definer, definers.all, definers[schema.type] || {});

  return definer;
};
Resource.timestamps = function () {
  this._timestamps = true;
  this.property('ctime');
  this.property('mtime');
};

Resource.define = function (schema) {
  return resourceful.mixin(this.schema, schema);
};

//
// Synchronize a Resource's design document with the database.
//
Resource.sync = function (callback) {
  var that = this,
      id   = ["_design", this.resource].join('/');

  this.once('sync', function (d) { callback(null, d) });

  if (this._synching) {
    return;
  }

  this._synching = true;
  this.connection.sync(this, function (e, design) {
    that._synching = false;
    that.emit('sync', design);
  });
};

//
// Prototype
//
Resource.prototype.save = function (callback) {
  var self = this;
  if (this.isValid) {
    this.constructor.save(this, function (err, res) {
      if (!err) {
        self.isNewRecord = false;
      }

      callback(err, res);
    });
  }
};

Resource.prototype.update = function (obj, callback) {
  return this.constructor.update(this._id, obj, callback);
};

Resource.prototype.saveAttachment = function (name, data, callback) {
  return this.constructor.saveAttachment(this._id, this._rev, name, data, callback);
};

Resource.prototype.destroy = function () {},
Resource.prototype.reload = function () {},
Resource.prototype.readProperty = function (k) {
  return this._properties[k];
};

Resource.prototype.writeProperty = function (k, val) {
  return this._properties[k] = val;
};

Resource.prototype.toJSON = function () {
  return resourceful.clone(this.properties);
};

Resource.prototype.inspect = function () {
  return util.inspect(this.properties);
};

Resource.prototype.toString = function () {
  return JSON.stringify(this.properties);
};

Resource.prototype.__defineGetter__('key', function () {
  return this[this.constructor.key];
});

Resource.prototype.__defineGetter__('id', function () {
  return this.constructor.key === '_id'
    ? this._id
    : undefined;
});

Resource.prototype.__defineGetter__('isValid', function () {
  return true;
});

Resource.prototype.__defineGetter__('properties', function () {
  return this._properties;
});

Resource.prototype.__defineSetter__('properties', function (props) {
  var self = this;
  Object.keys(props).forEach(function (k) {
    self[k] = props[k];
  });

  return props;
});
<commit_msg>[resource] Factory.createChild<commit_after>var events = require('events'),
    util = require('util'),
    validator = require('revalidator'),
    common = require('./common'),
    definers  = require('./definers')
    resourceful = require('../resourceful');;

//
// CRUD
//
var Resource = exports.Resource = function () {
  Object.defineProperty(this, 'isNewRecord', {
      value: true, writable: true
  });
};

//
// Hooks
//
Resource.after = function (event, callback) {
  this.hook(event, 'after', callback);
};
Resource.before = function (event, callback) {
  this.hook(event, 'before', callback);
};
Resource.hook = function (event, timing, callback) {
  this.hooks[timing][event] = this.hooks[timing][event] || [];
  this.hooks[timing][event].push(callback);
};
Resource.runBeforeHooks = function (method, obj, callback, finish) {
  if (method in this.hooks.before) {
    (function loop(hooks) {
      var hook = hooks.shift();

      if (hook) {
        hook(obj, function (e, obj) {
          if (e || obj) { callback(e, obj) }
          else          { loop(hooks) }
        });
      } else {
        finish();
      }
    })(this.hooks.before[method].slice(0));
  } else { finish() }
};
Resource.runAfterHooks = function (method, e, obj, finish) {
  if (method in this.hooks.before) {
    (function loop(hooks) {
      var hook = hooks.shift();

      if (hook) {
        hook(e, obj, function (e, obj) {
          if (e) { finish(e, obj) }
          else   { loop(hooks) }
        });
      } else {
        finish();
      }
    })(this.hooks.after[method].slice(0));
  } else { finish() }
};

//
// Raises the init event. Called from resourceful.define
//
Resource.init = function () {
  this.emit('init', this);
};

//
// Registers the current instance's resource with resourceful
//
Resource.register = function () {
  return resourceful.register(this.resource, this);
};

//
// Unregisters the current instance's resource from resourceful
//
Resource.unregister = function () {
  return resourceful.unregister(this.resource);
};

Resource._request = function (/* method, [key, obj], callback */) {
  var args     = Array.prototype.slice.call(arguments),
      that     = this,
      callback = args.pop(),
      method   = args.shift(),
      key      = args.shift(),
      obj      = args.shift();

  key && args.push(key);
  obj && args.push(obj.properties ? obj.properties : obj);

  this.runBeforeHooks(method, obj, callback, function () {
    args.push(function (e, result) {
      var Factory;

      if (e) {
        if (e.status >= 500) {
          throw new(Error)(e);
        } else {
          that.runAfterHooks(method, e, obj, function () {
            that.emit("error", e, obj);
            callback(e);
          });
        }
      } else {
        if (Array.isArray(result)) {
          result = result.map(function (r) {
            return resourceful.instantiate.call(that, r);
          });
        } else {
          if (method === 'destroy') {
            that.connection.cache.clear(key);
          } else {
            if (result.rev) {
              // Set the revision if available, so it can be saved
              // to the cache. If we're saving a new object,
              // '_rev' won't be a member of 'resource._properties'
              // so we need to set it here so resource.toJSON() includes it.
              if (obj instanceof resourceful.Resource && !obj._rev) {
                resourceful.defineProperty(obj, '_rev');
              }
              obj._rev = result.rev;
            }
            result = resourceful.instantiate.call(that, method === 'get' ? result : obj);

            if (method === 'update') {
              // TODO: Not necessary for identity map
              that.connection.cache.update(key, obj);
            } else {
              // TODO: We only need to do this if the key doesn't exist
              that.connection.cache.put(key, result);
            }
          }
        }
        that.runAfterHooks(method, null, obj, function (e, res) {
          if (e) { that.emit('error', e) }
          else   { that.emit(method, res || result) }
          callback(e || null, result);
        });
      }
    });
    that.connection[method].apply(that.connection, args);
  });
};

Resource.get = function (id, callback) {
  return id
    ? this._request('get', id, callback)
    : callback(new Error('key is undefined'));
};

Resource.create = function (attrs, callback) {
  if (this._timestamps) {
    attrs.ctime = attrs.mtime = Date.now()
  }

  // Before we create a new resource, perform a validation based on its schema
  var validate = validator.validate(attrs, {
    properties: this.schema.properties || {}
  });

  if (!validate.valid) {
    return callback(validate.errors);
  }

  var instance = new(this)(attrs);
  instance.save(function (e, res) {
    if (res) {
      instance._id  = instance._id  || res.id;
      instance._rev = instance._rev || res.rev;
    }

    callback(e, instance);
  });
};

Resource.save = function (obj, callback) {
  // Before we save a resource,  perform a validation based on its schema
  var validate = validator.validate(obj, {
    properties: this.schema.properties || {}
  });

  if (!validate.valid) {
    return callback(validate.errors);
  }

  if (this._timestamps) {
      obj.mtime = Date.now();
      if (obj.isNewRecord) { obj.ctime = obj.mtime }
  }

  return this._request("save", obj.key, obj, callback);
};

Resource.destroy = function (key, callback) {
  return this._request("destroy", key, callback);
};

Resource.update = function (key, obj, callback) {
  if (this._timestamps) { obj.mtime = Date.now() }
  return this._request("update", key, obj, callback);
};

Resource.all = function (callback) {
  return this._request("all", callback);
};

Resource.view = function (path, params, callback) {
  return this._request("view", path, params, callback);
};

Resource.filter = function (name, options, filter) {
  return this._request("filter",
                       name,
                       { options: options, filter: filter, resource: this },
                       function () {});
};

Resource.find = function (conditions, callback) {
  if (typeof(conditions) !== "object") {
      throw new(TypeError)("`find` takes an object as first argument.");
  }
  return this._request("find", conditions, callback);
};

Resource.use = function () {
  return resourceful.use.apply(this, arguments);
};

Resource.connect = function () {
  return resourceful.connect.apply(this, arguments);
};

// Define getter / setter for connection property
Resource.__defineGetter__('connection', function () {
  return this._connection || resourceful.connection;
});
Resource.__defineSetter__('connection', function (val) {
  return this._connection = val;
});

// Define getter / setter for engine property
Resource.__defineGetter__('engine', function () {
  return this._engine || resourceful.engine;
});
Resource.__defineSetter__('engine', function (val) {
  return this._engine = val;
});

// Define getter / setter for resource property
Resource.__defineGetter__('resource', function () {
  return this._resource;
});
Resource.__defineSetter__('resource', function (name) {
  return this._resource = name;
});

// Define getter for properties, wraps this resources schema properties
Resource.__defineGetter__('properties', function () {
  return this.schema.properties;
});

// Define getter / setter for key property. The key property is required by CouchDB
Resource.__defineSetter__('key', function (val) { return this._key = val });
Resource.__defineGetter__('key', function ()    { return this._key });

Resource.__defineGetter__('children', function (name) {
  return this._children.map(function (c) { return resourceful.resources[c] });
});
Resource.__defineGetter__('parents', function (name) {
  return this._parents.map(function (c) { return resourceful.resources[c] });
});

//
// many-to-many
//
// user.groups = [1,2,3,4,5]
//
// new(User).groups() // -> bulk GET on user.groups property
//                    // OR linked documents view
//                    // OR cache
//                    // - Define Users.byGroup(group_id)
//
// new(Group).users() // -> Users.byGroup(this._id) // view
//
// group = {};
//
// User.child('group')
// Group.child('user');
//

//
// Factory method for defining basic behaviour
//
function relationship(factory, type, r, optons) {
  var engine = factory.engine,
      rfactory,     // Resource factory/constructor
      rstring,      // Resource string
      rstringp,     // Resource pluralized string
      rstringc;     // Resource capitalized string

  if (typeof(r) === 'string') {
    rstring  = r;
    rfactory = resourceful.resources[resourceful.capitalize(r)];
  } else if (typeof(r) === 'function') {
    rstringc = r.resource;
    rstring = rstringc.toLowerCase();
    rfactory = r;
  } else {
    throw new(TypeError)("argument must be a string or constructor");
  }
  rstringp = resourceful.pluralize(rstring);
  rstringc = rstringc || resourceful.capitalize(rstring);

  if (factory._children.indexOf(rstringc) !== -1) { return }
  if (rfactory === undefined) throw new(Error)("unknown resource " + rstring);

  if (type == 'child') {
    factory._children.push(rstringc);
    factory.property(rstring + '_ids', Array, { default: [] });
    //
    // Parent.children(id, callback)
    //
    if (engine._children) {
      engine._children.call(this, factory, rstringp, rfactory);
    } else {
      factory[rstringp] = function (id, callback) {
        return rfactory['by' + factory.resource](id, callback);
      };
    }
    //
    // parent.children(callback)
    //
    factory.prototype[rstringp] = function (callback) {
      return this.constructor[rstringp](this._id, callback);
    };

    //
    // Parent.createChild(id, child, callback)
    //
    factory['create' + rstringc] = function (id, child, callback) {
      var key = factory.resource.toLowerCase() + '_id';
      if (child instanceof rfactory) {
        child[key] = id;
        child.save(callback);
      } else {
        var inheritance = {};
        inheritance[key] = id;
        child = resourceful.mixin({}, child, inheritance);
        rfactory.create(child, callback);
      }
    };

    //
    // parent.createChild(child, callback)
    //
    factory.prototype['create' + rstringc] = function (child, callback) {
      factory['create' + rstringc](this._id, child, callback);
    };
    rfactory.parent(factory);
  } else {
    factory._parents.push(rstringc);
    //
    // Child.byParent(id, callback)
    //
    if (engine._byParent) {
      engine._byParent.call(engine, factory, rstringc, rfactory);
    } else {
      factory['by' + rstringc] = engine._byParent || function (id, callback) {
        var filter = {};
        filter[rstring + '_id'] = id;

        factory.find(filter, callback);
      };
    }

    //
    // child.parent(callback)
    //
    factory.prototype[rstring] = function (callback) {
      return rfactory.get(this[rstring_id], callback);
    };
    factory.property(rstring + '_id', String, { default: null });

    rfactory.child(factory);
  }
};

//
// Entity relationships
//
Resource.child = function (resource, options) {
  relationship(this, 'child', resource, options);
};
Resource.parent = function (resource, options) {
  relationship(this, 'parent', resource, options);
};

Resource.property = function (name, typeOrSchema, schema) {
  var definer = {};
  var type = (function () {
    switch (typeof(typeOrSchema)) {
      case "string":    return typeOrSchema;
      case "function":  return typeOrSchema.name.toLowerCase();
      case "object":    schema = typeOrSchema;
      case "undefined": return "string";
      default:          throw new(Error)("Argument Error");
    }
  })();

  schema = schema || {};
  schema.type = schema.type || type;

  this.schema.properties[name] = definer.property = schema;
  definer.name = name;

  resourceful.mixin(definer, definers.all, definers[schema.type] || {});

  return definer;
};
Resource.timestamps = function () {
  this._timestamps = true;
  this.property('ctime');
  this.property('mtime');
};

Resource.define = function (schema) {
  return resourceful.mixin(this.schema, schema);
};

//
// Synchronize a Resource's design document with the database.
//
Resource.sync = function (callback) {
  var that = this,
      id   = ["_design", this.resource].join('/');

  this.once('sync', function (d) { callback(null, d) });

  if (this._synching) {
    return;
  }

  this._synching = true;
  this.connection.sync(this, function (e, design) {
    that._synching = false;
    that.emit('sync', design);
  });
};

//
// Prototype
//
Resource.prototype.save = function (callback) {
  var self = this;
  if (this.isValid) {
    this.constructor.save(this, function (err, res) {
      if (!err) {
        self.isNewRecord = false;
      }

      callback(err, res);
    });
  }
};

Resource.prototype.update = function (obj, callback) {
  return this.constructor.update(this._id, obj, callback);
};

Resource.prototype.saveAttachment = function (name, data, callback) {
  return this.constructor.saveAttachment(this._id, this._rev, name, data, callback);
};

Resource.prototype.destroy = function () {},
Resource.prototype.reload = function () {},
Resource.prototype.readProperty = function (k) {
  return this._properties[k];
};

Resource.prototype.writeProperty = function (k, val) {
  return this._properties[k] = val;
};

Resource.prototype.toJSON = function () {
  return resourceful.clone(this.properties);
};

Resource.prototype.inspect = function () {
  return util.inspect(this.properties);
};

Resource.prototype.toString = function () {
  return JSON.stringify(this.properties);
};

Resource.prototype.__defineGetter__('key', function () {
  return this[this.constructor.key];
});

Resource.prototype.__defineGetter__('id', function () {
  return this.constructor.key === '_id'
    ? this._id
    : undefined;
});

Resource.prototype.__defineGetter__('isValid', function () {
  return true;
});

Resource.prototype.__defineGetter__('properties', function () {
  return this._properties;
});

Resource.prototype.__defineSetter__('properties', function (props) {
  var self = this;
  Object.keys(props).forEach(function (k) {
    self[k] = props[k];
  });

  return props;
});
<|endoftext|>


<commit_before>/**
 * OUI core library.
 *
 * @octdoc      core/oui
 * @copyright   copyright (c) 2012 by Harald Lapp
 * @author      Harald Lapp <harald@octris.org>
 */
/**/

;(function(window) {
    if ('oui' in window) return;

    var oui = {};
    oui.$ = jQuery.noConflict();

    window.oui = oui;

    /**
     * Create a "UUID".
     *
     * @octdoc      oui/getUUID
     * @see         http://stackoverflow.com/a/105074/85582
     * @return      string                              The generated Id.
     */
    oui.getUUID = (function()
    /**/
    {
        var S4 = function() {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        }

        return function() {
            return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4());
        }
    })();
})(window);

<commit_msg>fixed documentation<commit_after>/**
 * OUI core library.
 *
 * @octdoc      core/oui
 * @copyright   copyright (c) 2012 by Harald Lapp
 * @author      Harald Lapp <harald@octris.org>
 */
/**/

;(function(window) {
    if ('oui' in window) return;

    var oui = {};
    oui.$ = jQuery.noConflict();

    window.oui = oui;

    /**
     * Create a "UUID".
     *
     * @octdoc  m:oui/getUUID
     * @see     http://stackoverflow.com/a/105074/85582
     * @return  string                              The generated Id.
     */
    oui.getUUID = (function()
    /**/
    {
        var S4 = function() {
            return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
        }

        return function() {
            return (S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4());
        }
    })();
})(window);

<|endoftext|>