<commit_before>(function() {
    // Get application context
    var app = Sammy.apps['#main'];
    var store = app.store;

    /**
     * Apps
     *
     */

    // List installed apps
    app.get('#/apps', function (c) {
        c.api('/apps?installed', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8
            apps = data['apps'];
            c.arraySortById(apps);
            c.view('app/app_list', {apps: apps});
        });
    });

    // List available apps
    app.get('#/apps/install', function (c) {
        c.api('/apps', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8
            c.api('/apps?raw', function(dataraw) { // http://api.yunohost.org/#!/app/app_list_get_8
                apps = [];
                $.each(data['apps'], function(k, v) {
                    // Keep only uninstalled apps, or multi-instance apps
                    if ((!v['installed'] || dataraw[v['id']].manifest.multi_instance == "true") && !v['id'].match(/__[0-9]{1,5}$/)) {
                        // Check app source
                        dataraw[v['id']]['official'] = (dataraw[v['id']]['repository'] == 'yunohost');

                        jQuery.extend(dataraw[v['id']], v);
                        apps.push(dataraw[v['id']]);
                    }
                });

                // Sort app list
                c.arraySortById(apps);
                c.view('app/app_list_install', {apps: apps});
            });
        });
    });

    // Refresh available apps list
    app.get('#/apps/refresh', function (c) {
        c.api('/appslists', function(data) { // http://api.yunohost.org/#!/app/app_fetchlist_put_5
            // c.redirect(store.get('path'));
            c.redirect('#/apps/install');
        }, 'PUT');
    });

    // Get app information
    app.get('#/apps/:app', function (c) {
        c.api('/apps/'+c.params['app']+'?raw', function(data) { // http://api.yunohost.org/#!/app/app_info_get_9
            // Presentation
            data.settings.allowed_users = (data.settings.allowed_users) ? data.settings.allowed_users.replace(',', ', ')+"." : y18n.t('everyone_has_access');

            // Multilingual description
            data.description = (typeof data.manifest.description[y18n.locale] !== 'undefined') ?
                        data.manifest.description[y18n.locale] :
                        data.manifest.description['en']
                        ;

            // Multi Instance settings
            data.manifest.multi_instance = (data.manifest.multi_instance == 'true') ? y18n.t('yes') : y18n.t('no');

            // Installation date
            var d = new Date(data.settings.install_time * 1000);
            data.install_time = d.getDate() + '/' + (d.getMonth()+1) + '/' + d.getFullYear();

            c.view('app/app_info', data);
        });
    });

    // Get app debug page
    app.get('#/apps/:app/debug', function (c) {
        c.api('/apps/'+c.params['app']+'/debug', function(data) {
            c.view('app/app_debug', data);
        });
    });

    // Special case for custom app installation.
    app.get('#/apps/install/custom', function (c) {
        // If we try to GET /apps/install/custom, it means that installation fail.
        // Need to redirect to apps/install to get rid of pacamn and see the log.
        c.redirect('#/apps/install');
    });

    // Helper function that build app installation form
    app.helper('appInstallForm', function(appId, manifest, params) {
        data = {
            id: appId,
            manifest: manifest
        };

        if (typeof data.manifest.arguments.install !== 'undefined') {
            $.each(data.manifest.arguments.install, function(k, v) {

                // Default values
                data.manifest.arguments.install[k].type = (typeof v.type !== 'undefined') ? v.type : 'string';
                data.manifest.arguments.install[k].inputType = 'text';
                data.manifest.arguments.install[k].required = (typeof v.optional !== 'undefined' && v.optional == "true") ? '' : 'required';
                data.manifest.arguments.install[k].attributes = "";

                // Input with choices becomes select list
                if (typeof data.manifest.arguments.install[k].choices !== 'undefined') {
                    // Update choices values with  key and checked data
                    $.each(data.manifest.arguments.install[k].choices, function(ck, cv){
                        data.manifest.arguments.install[k].choices[ck] = {
                            value: cv,
                            label: cv,
                            selected: (cv == data.manifest.arguments.install[k].default) ? true : false,
                        };
                    });
                }

                // Special case for domain input.
                // Display a list of available domains
                if (v.name == 'domain' || data.manifest.arguments.install[k].type == 'domain') {
                    data.manifest.arguments.install[k].choices = [];
                    $.each(params.domains, function(key, domain){
                        data.manifest.arguments.install[k].choices.push({
                            value: domain,
                            label: domain,
                            selected: false
                        });
                    });
                    data.manifest.arguments.install[k].help = "<a href='#/domains'>"+y18n.t('manage_domains')+"</a>";
                }

                // Special case for admin / user input.
                // Display a list of available users
                if (v.name == 'admin' || data.manifest.arguments.install[k].type == 'user') {
                    data.manifest.arguments.install[k].choices = [];
                    $.each(params.users, function(username, user){
                        data.manifest.arguments.install[k].choices.push({
                            value: username,
                            label: user.fullname+' ('+user.mail+')',
                            selected: false
                        });
                    });
                    data.manifest.arguments.install[k].help = "<a href='#/users'>"+y18n.t('manage_users')+"</a>";
                }

                // 'app' type input display a list of available apps
                if (data.manifest.arguments.install[k].type == 'app') {
                    data.manifest.arguments.install[k].choices = [];
                    $.each(params.apps, function(key, app){
                        data.manifest.arguments.install[k].choices.push({
                            value: app.id,
                            label: app.name,
                            selected: false
                        });
                    });
                    data.manifest.arguments.install[k].help = "<a href='#/apps'>"+y18n.t('manage_apps')+"</a>";
                }

                // Boolean fields
                if (data.manifest.arguments.install[k].type == 'boolean') {
                    data.manifest.arguments.install[k].inputType = 'checkbox';

                    // Checked or not ?
                    if (typeof data.manifest.arguments.install[k].default !== 'undefined') {
                        if (data.manifest.arguments.install[k].default == true) {
                            data.manifest.arguments.install[k].attributes = 'checked="checked"';
                        }
                    }

                    // 'default' is used as value, so we need to force it for checkboxes.
                    data.manifest.arguments.install[k].default = 1;

                    // Checkbox should not be required to be unchecked
                    data.manifest.arguments.install[k].required = '';
                }

                // 'password' type input.
                if (v.name == 'password' || data.manifest.arguments.install[k].type == 'password') {
                    // Change html input type
                    data.manifest.arguments.install[k].inputType = 'password';
                }


                // Multilingual label
                data.manifest.arguments.install[k].label = (typeof data.manifest.arguments.install[k].ask[y18n.locale] !== 'undefined') ?
                                    data.manifest.arguments.install[k].ask[y18n.locale] :
                                    data.manifest.arguments.install[k].ask['en']
                                    ;
            });
        }

        // Multilingual description
        data.description = (typeof data.manifest.description[y18n.locale] !== 'undefined') ?
                                data.manifest.description[y18n.locale] :
                                data.manifest.description['en']
                                ;

        // Multi Instance settings boolean to text
        data.manifest.multi_instance = (data.manifest.multi_instance == 'true') ? y18n.t('yes') : y18n.t('no');

        // View app install form
        c.view('app/app_install', data);
        return;
    });

    // App installation form
    app.get('#/apps/install/:app', function (c) {
        c.api('/apps?raw', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8

            c.appInstallForm(
                c.params['app'],
                data[c.params['app']].manifest,
                c.params
            );

        });
    });

    // Install app (POST)
    app.post('#/apps', function(c) {
        // Warn admin if app is going to be installed on domain root.
        if (c.params['path'] !== '/' || confirm(y18n.t('confirm_install_domain_root', [c.params['domain']]))) {
            params = { 'label': c.params['label'], 'app': c.params['app'] };
            delete c.params['label'];
            delete c.params['app'];
            params['args'] = c.serialize(c.params.toHash());
            // Do not pass empty args.
            if (params['args'] === "") {
                delete params['args'];
            }

            c.api('/apps', function() { // http://api.yunohost.org/#!/app/app_install_post_2
                c.redirect('#/apps');
            }, 'POST', params);
        }
        else {
            c.flash('warning', y18n.t('app_install_cancel'));
            store.clear('slide');
            c.redirect('#/apps/install');
        }
    });

    // Install custom app from github
    app.post('#/apps/install/custom', function(c) {
<commit_msg>[fix] Allow checkbox to be unchecked even if default is true.<commit_after>(function() {
    // Get application context
    var app = Sammy.apps['#main'];
    var store = app.store;

    /**
     * Apps
     *
     */

    // List installed apps
    app.get('#/apps', function (c) {
        c.api('/apps?installed', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8
            apps = data['apps'];
            c.arraySortById(apps);
            c.view('app/app_list', {apps: apps});
        });
    });

    // List available apps
    app.get('#/apps/install', function (c) {
        c.api('/apps', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8
            c.api('/apps?raw', function(dataraw) { // http://api.yunohost.org/#!/app/app_list_get_8
                apps = [];
                $.each(data['apps'], function(k, v) {
                    // Keep only uninstalled apps, or multi-instance apps
                    if ((!v['installed'] || dataraw[v['id']].manifest.multi_instance == "true") && !v['id'].match(/__[0-9]{1,5}$/)) {
                        // Check app source
                        dataraw[v['id']]['official'] = (dataraw[v['id']]['repository'] == 'yunohost');

                        jQuery.extend(dataraw[v['id']], v);
                        apps.push(dataraw[v['id']]);
                    }
                });

                // Sort app list
                c.arraySortById(apps);
                c.view('app/app_list_install', {apps: apps});
            });
        });
    });

    // Refresh available apps list
    app.get('#/apps/refresh', function (c) {
        c.api('/appslists', function(data) { // http://api.yunohost.org/#!/app/app_fetchlist_put_5
            // c.redirect(store.get('path'));
            c.redirect('#/apps/install');
        }, 'PUT');
    });

    // Get app information
    app.get('#/apps/:app', function (c) {
        c.api('/apps/'+c.params['app']+'?raw', function(data) { // http://api.yunohost.org/#!/app/app_info_get_9
            // Presentation
            data.settings.allowed_users = (data.settings.allowed_users) ? data.settings.allowed_users.replace(',', ', ')+"." : y18n.t('everyone_has_access');

            // Multilingual description
            data.description = (typeof data.manifest.description[y18n.locale] !== 'undefined') ?
                        data.manifest.description[y18n.locale] :
                        data.manifest.description['en']
                        ;

            // Multi Instance settings
            data.manifest.multi_instance = (data.manifest.multi_instance == 'true') ? y18n.t('yes') : y18n.t('no');

            // Installation date
            var d = new Date(data.settings.install_time * 1000);
            data.install_time = d.getDate() + '/' + (d.getMonth()+1) + '/' + d.getFullYear();

            c.view('app/app_info', data);
        });
    });

    // Get app debug page
    app.get('#/apps/:app/debug', function (c) {
        c.api('/apps/'+c.params['app']+'/debug', function(data) {
            c.view('app/app_debug', data);
        });
    });

    // Special case for custom app installation.
    app.get('#/apps/install/custom', function (c) {
        // If we try to GET /apps/install/custom, it means that installation fail.
        // Need to redirect to apps/install to get rid of pacamn and see the log.
        c.redirect('#/apps/install');
    });

    // Helper function that build app installation form
    app.helper('appInstallForm', function(appId, manifest, params) {
        data = {
            id: appId,
            manifest: manifest
        };

        if (typeof data.manifest.arguments.install !== 'undefined') {
            $.each(data.manifest.arguments.install, function(k, v) {

                // Default values
                data.manifest.arguments.install[k].type = (typeof v.type !== 'undefined') ? v.type : 'string';
                data.manifest.arguments.install[k].inputType = 'text';
                data.manifest.arguments.install[k].required = (typeof v.optional !== 'undefined' && v.optional == "true") ? '' : 'required';
                data.manifest.arguments.install[k].attributes = "";

                // Input with choices becomes select list
                if (typeof data.manifest.arguments.install[k].choices !== 'undefined') {
                    // Update choices values with  key and checked data
                    $.each(data.manifest.arguments.install[k].choices, function(ck, cv){
                        data.manifest.arguments.install[k].choices[ck] = {
                            value: cv,
                            label: cv,
                            selected: (cv == data.manifest.arguments.install[k].default) ? true : false,
                        };
                    });
                }

                // Special case for domain input.
                // Display a list of available domains
                if (v.name == 'domain' || data.manifest.arguments.install[k].type == 'domain') {
                    data.manifest.arguments.install[k].choices = [];
                    $.each(params.domains, function(key, domain){
                        data.manifest.arguments.install[k].choices.push({
                            value: domain,
                            label: domain,
                            selected: false
                        });
                    });
                    data.manifest.arguments.install[k].help = "<a href='#/domains'>"+y18n.t('manage_domains')+"</a>";
                }

                // Special case for admin / user input.
                // Display a list of available users
                if (v.name == 'admin' || data.manifest.arguments.install[k].type == 'user') {
                    data.manifest.arguments.install[k].choices = [];
                    $.each(params.users, function(username, user){
                        data.manifest.arguments.install[k].choices.push({
                            value: username,
                            label: user.fullname+' ('+user.mail+')',
                            selected: false
                        });
                    });
                    data.manifest.arguments.install[k].help = "<a href='#/users'>"+y18n.t('manage_users')+"</a>";
                }

                // 'app' type input display a list of available apps
                if (data.manifest.arguments.install[k].type == 'app') {
                    data.manifest.arguments.install[k].choices = [];
                    $.each(params.apps, function(key, app){
                        data.manifest.arguments.install[k].choices.push({
                            value: app.id,
                            label: app.name,
                            selected: false
                        });
                    });
                    data.manifest.arguments.install[k].help = "<a href='#/apps'>"+y18n.t('manage_apps')+"</a>";
                }

                // Boolean fields
                if (data.manifest.arguments.install[k].type == 'boolean') {
                    data.manifest.arguments.install[k].inputType = 'checkbox';

                    // Checked or not ?
                    if (typeof data.manifest.arguments.install[k].default !== 'undefined') {
                        if (data.manifest.arguments.install[k].default == true) {
                            data.manifest.arguments.install[k].attributes = 'checked="checked"';
                        }
                    }

                    // 'default' is used as value, so we need to force it for checkboxes.
                    data.manifest.arguments.install[k].default = 1;

                    // Checkbox should not be required to be unchecked
                    data.manifest.arguments.install[k].required = '';

                    // Clone a hidden input with empty value
                    // https://stackoverflow.com/questions/476426/submit-an-html-form-with-empty-checkboxes
                    inputClone = {};
                    inputClone.name = data.manifest.arguments.install[k].name;
                    inputClone.inputType = 'hidden';
                    inputClone.default = 0;
                    data.manifest.arguments.install.push(inputClone);
                }

                // 'password' type input.
                if (v.name == 'password' || data.manifest.arguments.install[k].type == 'password') {
                    // Change html input type
                    data.manifest.arguments.install[k].inputType = 'password';
                }


                // Multilingual label
                data.manifest.arguments.install[k].label = (typeof data.manifest.arguments.install[k].ask[y18n.locale] !== 'undefined') ?
                                    data.manifest.arguments.install[k].ask[y18n.locale] :
                                    data.manifest.arguments.install[k].ask['en']
                                    ;
            });
        }

        // Multilingual description
        data.description = (typeof data.manifest.description[y18n.locale] !== 'undefined') ?
                                data.manifest.description[y18n.locale] :
                                data.manifest.description['en']
                                ;

        // Multi Instance settings boolean to text
        data.manifest.multi_instance = (data.manifest.multi_instance == 'true') ? y18n.t('yes') : y18n.t('no');

        // View app install form
        c.view('app/app_install', data);
        return;
    });

    // App installation form
    app.get('#/apps/install/:app', function (c) {
        c.api('/apps?raw', function(data) { // http://api.yunohost.org/#!/app/app_list_get_8

            c.appInstallForm(
                c.params['app'],
                data[c.params['app']].manifest,
                c.params
            );

        });
    });

    // Install app (POST)
    app.post('#/apps', function(c) {
        // Warn admin if app is going to be installed on domain root.
        if (c.params['path'] !== '/' || confirm(y18n.t('confirm_install_domain_root', [c.params['domain']]))) {
            params = { 'label': c.params['label'], 'app': c.params['app'] };
            delete c.params['label'];
            delete c.params['app'];

            // Check for duplicate arg produced by empty checkbox. (See inputClone)
            $.each(c.params, function(k, v) {
                if (typeof(v) === 'object' && Array.isArray(v)) {
                    // And return only first value
                    c.params[k] = v[0];
                }
            });

            params['args'] = c.serialize(c.params.toHash());
            // Do not pass empty args.
            if (params['args'] === "") {
                delete params['args'];
            }

            c.api('/apps', function() { // http://api.yunohost.org/#!/app/app_install_post_2
                c.redirect('#/apps');
            }, 'POST', params);
        }
        else {
            c.flash('warning', y18n.t('app_install_cancel'));
            store.clear('slide');
            c.redirect('#/apps/install');
        }
    });

    // Install custom app from github
    app.post('#/apps/install/custom', function(c) {

{'fraction_non_alphanumeric': 0.15190340123513688, 'fraction_numerical': 0.004885242879528067, 'mean_word_length': 1.4638355853298513, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6183624', 'n_tokens_mistral': 6074, 'n_tokens_neox': 5630, 'n_words': 1040}