<commit_before>// -*- coding: utf-8 -*-
//
// Copyright 2015 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

'use strict';

var app = angular.module('app', ['ngRoute', 'restangular', 'ngCookies',
'angular-loading-bar', 'ui.router']);

// Configure the application
app.config(function(RestangularProvider) {
    RestangularProvider.setBaseUrl('/api');
    // https://github.com/mgonto/restangular#my-response-is-actually-wrapped-with-some-metadata-how-do-i-get-the-data-in-that-case
    RestangularProvider.addResponseInterceptor(function(
    data, operation, what, url, response, deferred) {
        var extractedData = [];
        if (operation === 'getList') {
            extractedData._items = data._items;
            extractedData._meta = data._meta;
        } else {
            extractedData = data;
        }
        return extractedData;
    });
});

app.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
    $stateProvider
    .state('jobs', {
        url: '/jobs?page',
        templateUrl: 'partials/jobs.html',
        controller: 'ListJobsController'
    }).state('jobdetails', {
        url:'/jobdetails/:jobId',
        templateUrl: 'partials/jobdetails.html',
        controller: 'JobDetailsController'
    }).state('remotecis', {
        url:'/remotecis',
        templateUrl: 'partials/remotecis.html',
        controller: 'ListRemotecisController'
    }).state('products', {
        url:'/products',
        templateUrl: 'partials/products.html',
        controller: 'ProductsController'
    }).state('signin', {
        url: '/signin',
        templateUrl: 'partials/signin.html',
        controller: 'LoginController'
    }).state('signout', {
        url: '/signout',
        templateUrl: 'partials/signout.html',
        controller: 'LogoutController'
    });

    $urlRouterProvider.otherwise('/jobs');
    $httpProvider.interceptors.push('BasicAuthInjector');
});

app.factory('CommonCode', function($window, Restangular, $cookies) {
    // jscs:disable requireCamelCaseOrUpperCaseIdentifiers

    var getRemoteCis = function($scope) {
        Restangular.one('remotecis').get().then(
            function(remotecis) {
                $scope.remotecis = remotecis._items;
                $cookies.remotecisTotalPages = parseInt((
                remotecis._meta.total / remotecis._meta.max_results + 1));
                $scope.remotecisTotalPages = $cookies.remotecisTotalPages;
            }
        );
    };

    var getJobInfo = function($scope, job_id) {
        Restangular.one('jobs', job_id).get(
        {'embedded': {'remoteci':1, 'testversion':1}}).then(
        function(job) {
            $scope.job = job;
            Restangular.one('jobstates').get(
                {'where': {'job_id': job_id},
                 'embedded': {'files_collection':1}}).then(
                 function(jobstates) {
                     $scope.job['jobstates'] = jobstates._items;
                 });

            Restangular.one('testversions', job.testversion.id).get(
                {'embedded': {'version':1, 'test':1}}).then(
                function(testversion) {
                    $scope.job['version'] = testversion.version.name;
                    $scope.job['test'] = testversion.test.name;
                    Restangular.one('products',
                    testversion.version.product_id).get().then(
                        function(product) {
                            $scope.job['product'] = product.name;
                        }
                )});
        });
    };

    return {'getJobInfo': getJobInfo,
            'getRemoteCis': getRemoteCis};
});

app.factory('BasicAuthInjector', function($cookies) {
    var injector = {
        request: function(config) {
            config.headers['Authorization'] = 'Basic ' + $cookies.auth;
            return config;
        }
    };
    return injector;
});

app.controller('ListJobsController', function($scope, $location, $cookies,
CommonCode, Restangular, $state, $stateParams) {

    var loadPage = function() {
        var targetPage = $scope.jobCurrentPage;
        var searchObject = $location.search();
        if (searchObject.page != undefined) {
            var totalPages = $cookies.jobsTotalPages;
            var pageNumber = parseInt(searchObject.page);

            if ((pageNumber < ((parseInt(totalPages) + 1) | 0)) &&
                (pageNumber > 1)) {
                targetPage = parseInt(searchObject.page);
                $scope.jobCurrentPage = targetPage;
            }
        }

        Restangular.one('jobs').get({'page': targetPage, 'extra_data': 1}).
        then(function(jobs) {
            $scope.jobs = jobs._items
            $cookies.jobsTotalPages = parseInt((jobs._meta.total /
                jobs._meta.max_results + 1));
            $scope.jobsTotalPages = $cookies.jobsTotalPages;
        });

    };

    $scope.jobsNextPage = function() {
        if ($scope.jobCurrentPage < $cookies.jobsTotalPages) {
            $scope.jobCurrentPage++;
            $state.go('jobs', {page:$scope.jobCurrentPage});
        }
    }

    $scope.jobsPreviousPage = function() {
        if ($scope.jobCurrentPage > 1) {
            $scope.jobCurrentPage--;
            $state.go('jobs', {page:$scope.jobCurrentPage});
        }
    }

    if ($scope.jobCurrentPage == undefined) {
        $scope.jobCurrentPage = 1;
    }

    loadPage();
});

app.controller('ListRemotecisController', function($scope, $location,
CommonCode, Restangular) {

    $scope.remotecisNextPage = function() {
        if ($scope.remoteciCurrentPage < $cookies.remotecisTotalPages) {
            $scope.remoteciCurrentPage++;
            $state.go('jobs', {page:$scope.jobCurrentPage});
        }
    }

    $scope.remotecisPreviousPage = function() {
        if ($scope.remoteciCurrentPage > 1) {
            $scope.remoteciCurrentPage--;
            $state.go('jobs', {page:$scope.remoteciCurrentPage});
        }
    }

    if ($scope.remoteciCurrentPage == undefined) {
        $scope.remoteciCurrentPage = 1;
    }
    CommonCode.getRemoteCis($scope);
});

app.controller('JobDetailsController', function(
    $scope, CommonCode, Restangular, $stateParams) {
    CommonCode.getJobInfo($scope, $stateParams.jobId);
});

app.controller('ProductsController', function(
    $scope, CommonCode, Restangular, $stateParams) {

    Restangular.one('products').get().
        then(function(products) {
            $scope.products = products._items;
            $scope.myProduct = products._items[0];
        });

    $scope.$watch('myProduct', function(currentProduct, previousProduct) {
        if (currentProduct != undefined) {
            console.log(currentProduct.id);
            Restangular.one('versions').
            get({'where': {'product_id': currentProduct.id}, 'extra_data': 1}).
            then(function(versions) {
                $scope.versions_status = versions._items;
            });
        }
    });
});

app.controller('LoginController', ['$scope', '$cookies', '$state',
    function($scope, $cookies, $state) {
        $scope.submit = function() {
            var loginb64 = btoa($scope.username.concat(':', $scope.password));
            $cookies.auth = loginb64;
            $state.go('jobs');
        };
    }
]);

app.controller('LogoutController', ['$scope', '$templateCache',
'$cookies', '$state',
  function($scope, $templateCache, $cookies, $state) {
      $templateCache.removeAll();
      $cookies.auth = btoa('None');
      $state.go('jobs');
  }
]);
<commit_msg>js: show the last jobs first<commit_after>// -*- coding: utf-8 -*-
//
// Copyright 2015 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

'use strict';

var app = angular.module('app', ['ngRoute', 'restangular', 'ngCookies',
'angular-loading-bar', 'ui.router']);

// Configure the application
app.config(function(RestangularProvider) {
    RestangularProvider.setBaseUrl('/api');
    // https://github.com/mgonto/restangular#my-response-is-actually-wrapped-with-some-metadata-how-do-i-get-the-data-in-that-case
    RestangularProvider.addResponseInterceptor(function(
    data, operation, what, url, response, deferred) {
        var extractedData = [];
        if (operation === 'getList') {
            extractedData._items = data._items;
            extractedData._meta = data._meta;
        } else {
            extractedData = data;
        }
        return extractedData;
    });
});

app.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
    $stateProvider
    .state('jobs', {
        url: '/jobs?page',
        templateUrl: 'partials/jobs.html',
        controller: 'ListJobsController'
    }).state('jobdetails', {
        url:'/jobdetails/:jobId',
        templateUrl: 'partials/jobdetails.html',
        controller: 'JobDetailsController'
    }).state('remotecis', {
        url:'/remotecis',
        templateUrl: 'partials/remotecis.html',
        controller: 'ListRemotecisController'
    }).state('products', {
        url:'/products',
        templateUrl: 'partials/products.html',
        controller: 'ProductsController'
    }).state('signin', {
        url: '/signin',
        templateUrl: 'partials/signin.html',
        controller: 'LoginController'
    }).state('signout', {
        url: '/signout',
        templateUrl: 'partials/signout.html',
        controller: 'LogoutController'
    });

    $urlRouterProvider.otherwise('/jobs');
    $httpProvider.interceptors.push('BasicAuthInjector');
});

app.factory('CommonCode', function($window, Restangular, $cookies) {
    // jscs:disable requireCamelCaseOrUpperCaseIdentifiers

    var getRemoteCis = function($scope) {
        Restangular.one('remotecis').get().then(
            function(remotecis) {
                $scope.remotecis = remotecis._items;
                $cookies.remotecisTotalPages = parseInt((
                remotecis._meta.total / remotecis._meta.max_results + 1));
                $scope.remotecisTotalPages = $cookies.remotecisTotalPages;
            }
        );
    };

    var getJobInfo = function($scope, job_id) {
        Restangular.one('jobs', job_id).get(
        {'embedded': {'remoteci':1, 'testversion':1}}).then(
        function(job) {
            $scope.job = job;
            Restangular.one('jobstates').get(
                {'where': {'job_id': job_id},
                 'embedded': {'files_collection':1}}).then(
                 function(jobstates) {
                     $scope.job['jobstates'] = jobstates._items;
                 });

            Restangular.one('testversions', job.testversion.id).get(
                {'embedded': {'version':1, 'test':1}}).then(
                function(testversion) {
                    $scope.job['version'] = testversion.version.name;
                    $scope.job['test'] = testversion.test.name;
                    Restangular.one('products',
                    testversion.version.product_id).get().then(
                        function(product) {
                            $scope.job['product'] = product.name;
                        }
                )});
        });
    };

    return {'getJobInfo': getJobInfo,
            'getRemoteCis': getRemoteCis};
});

app.factory('BasicAuthInjector', function($cookies) {
    var injector = {
        request: function(config) {
            config.headers['Authorization'] = 'Basic ' + $cookies.auth;
            return config;
        }
    };
    return injector;
});

app.controller('ListJobsController', function($scope, $location, $cookies,
CommonCode, Restangular, $state, $stateParams) {

    var loadPage = function() {
        var targetPage = $scope.jobCurrentPage;
        var searchObject = $location.search();
        if (searchObject.page != undefined) {
            var totalPages = $cookies.jobsTotalPages;
            var pageNumber = parseInt(searchObject.page);

            if ((pageNumber < ((parseInt(totalPages) + 1) | 0)) &&
                (pageNumber > 1)) {
                targetPage = parseInt(searchObject.page);
                $scope.jobCurrentPage = targetPage;
            }
        }

        Restangular.one('jobs').get({'page': targetPage,
                                     'extra_data': 1,
                                     'sort': '-created_at'}).
        then(function(jobs) {
            $scope.jobs = jobs._items
            $cookies.jobsTotalPages = parseInt((jobs._meta.total /
                jobs._meta.max_results + 1));
            $scope.jobsTotalPages = $cookies.jobsTotalPages;
        });

    };

    $scope.jobsNextPage = function() {
        if ($scope.jobCurrentPage < $cookies.jobsTotalPages) {
            $scope.jobCurrentPage++;
            $state.go('jobs', {page:$scope.jobCurrentPage});
        }
    }

    $scope.jobsPreviousPage = function() {
        if ($scope.jobCurrentPage > 1) {
            $scope.jobCurrentPage--;
            $state.go('jobs', {page:$scope.jobCurrentPage});
        }
    }

    if ($scope.jobCurrentPage == undefined) {
        $scope.jobCurrentPage = 1;
    }

    loadPage();
});

app.controller('ListRemotecisController', function($scope, $location,
CommonCode, Restangular) {

    $scope.remotecisNextPage = function() {
        if ($scope.remoteciCurrentPage < $cookies.remotecisTotalPages) {
            $scope.remoteciCurrentPage++;
            $state.go('jobs', {page:$scope.jobCurrentPage});
        }
    }

    $scope.remotecisPreviousPage = function() {
        if ($scope.remoteciCurrentPage > 1) {
            $scope.remoteciCurrentPage--;
            $state.go('jobs', {page:$scope.remoteciCurrentPage});
        }
    }

    if ($scope.remoteciCurrentPage == undefined) {
        $scope.remoteciCurrentPage = 1;
    }
    CommonCode.getRemoteCis($scope);
});

app.controller('JobDetailsController', function(
    $scope, CommonCode, Restangular, $stateParams) {
    CommonCode.getJobInfo($scope, $stateParams.jobId);
});

app.controller('ProductsController', function(
    $scope, CommonCode, Restangular, $stateParams) {

    Restangular.one('products').get().
        then(function(products) {
            $scope.products = products._items;
            $scope.myProduct = products._items[0];
        });

    $scope.$watch('myProduct', function(currentProduct, previousProduct) {
        if (currentProduct != undefined) {
            console.log(currentProduct.id);
            Restangular.one('versions').
            get({'where': {'product_id': currentProduct.id}, 'extra_data': 1}).
            then(function(versions) {
                $scope.versions_status = versions._items;
            });
        }
    });
});

app.controller('LoginController', ['$scope', '$cookies', '$state',
    function($scope, $cookies, $state) {
        $scope.submit = function() {
            var loginb64 = btoa($scope.username.concat(':', $scope.password));
            $cookies.auth = loginb64;
            $state.go('jobs');
        };
    }
]);

app.controller('LogoutController', ['$scope', '$templateCache',
'$cookies', '$state',
  function($scope, $templateCache, $cookies, $state) {
      $templateCache.removeAll();
      $cookies.auth = btoa('None');
      $state.go('jobs');
  }
]);
<|endoftext|>


<commit_before>// (C) Copyright 2015 Martin Dougiamas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

angular.module('mm.core.sharedfiles')

.factory('$mmSharedFilesHelper', function($mmSharedFiles, $mmUtil, $log, $mmApp, $mmSitesManager, $mmFS, $rootScope, $q,
            $ionicModal, $state, $translate) {

    $log = $log.getInstance('$mmSharedFilesHelper');

    var self = {};

    /**
     * Ask a user if he wants to replace a file (using originalName) or rename it (using newName).
     *
     * @module mm.core.sharedfiles
     * @ngdoc method
     * @name $mmSharedFilesHelper#askRenameReplace
     * @param  {String} originalName Original name.
     * @param  {String} newName      New name.
     * @return {Promise}             Promise resolved with the name to use when the user chooses. Rejected if user cancels.
     */
    self.askRenameReplace = function(originalName, newName) {
        var scope = $rootScope.$new();
        scope.originalName = originalName;
        scope.newName = newName;

        return $ionicModal.fromTemplateUrl('core/components/sharedfiles/templates/renamereplace.html', {
            scope: scope,
            animation: 'slide-in-up'
        }).then(function(modal) {
            var deferred = $q.defer();

            scope.modal = modal;
            modal.show();

            scope.click = function(name) {
                close();
                deferred.resolve(name);
            };

            scope.closeModal = function() {
                close();
                deferred.reject();
            };

            function close() {
                modal.remove();
                scope.$destroy();
            }

            return deferred.promise;
        });
    };

    /**
     * Go to the choose site view.
     *
     * @module mm.core.sharedfiles
     * @ngdoc method
     * @name $mmSharedFilesHelper#goToChooseSite
     * @param  {String} filePath File path to send to the view.
     * @return {Promise}         Promise resolved when state changed.
     */
    self.goToChooseSite = function(filePath) {
        var parentState = $state.$current.name.split('.')[0];
        return $state.go(parentState + '.sharedfiles-choose-site', {filepath: filePath});
    };

    /**
     * Checks if there is a new file received in iOS and move it to the shared folder of current site.
     * If more than one site is found, the user will have to choose the site where to store it in.
     * If more than one file is found, treat only the first one.
     *
     * @module mm.core.sharedfiles
     * @ngdoc method
     * @name $mmSharedFilesHelper#searchIOSNewSharedFiles
     * @return {Promise} Promise resolved when done.
     */
    self.searchIOSNewSharedFiles = function() {
        return $mmApp.ready().then(function() {
            return $mmSharedFiles.checkIOSNewFiles().then(function(fileEntry) {
                return $mmSitesManager.getSitesIds().then(function(siteIds) {
                    if (!siteIds.length) {
                        // No sites stored, show error and delete the file.
                        $mmUtil.showErrorModal('mm.sharedfiles.errorreceivefilenosites', true);
                        $mmSharedFiles.deleteInboxFile(fileEntry);
                    } else if (siteIds.length == 1) {
                        self.storeSharedFileInSite(fileEntry, siteIds[0]);
                    } else {
                        self.goToChooseSite(fileEntry.fullPath);
                    }
                });
            });
        });
    };

    /**
     * Store a shared file in a site's shared files folder.
     *
     * @module mm.core.sharedfiles
     * @ngdoc method
     * @name $mmSharedFilesHelper#storeSharedFileInSite
     * @param  {Object} fileEntry Shared file entry.
     * @param  {String} [siteId]  Site ID. If not defined, current site.
     * @return {promise}          Promise resolved when done.
     */
    self.storeSharedFileInSite = function(fileEntry, siteId) {
        siteId = siteId || $mmSite.getId();

        // First of all check if there's already a file with the same name in the shared files folder.
        return $mmSharedFiles.getSiteSharedFiles(siteId).then(function(entries) {
            var files = {};

            // Index the files by name.
            angular.forEach(entries, function(entry) {
                files[entry.name] = entry;
            });

            if (typeof files[fileEntry.name] == 'undefined') {
                // No file with the same name. Use the original file name.
                return fileEntry.name;
            } else {
                // Repeated name. Add a number until we find a free name.
                var newName,
                    number = 1,
                    extension = $mmFS.getFileExtension(fileEntry.name),
                    nameWithoutExtension = fileEntry.name.substr(0, fileEntry.name.length - extension.length - 1);

                do {
                    newName = nameWithoutExtension + '(' + number + ').' + extension;
                    number++;
                } while (typeof files[newName] != 'undefined');

                // Ask the user what he wants to do.
                return self.askRenameReplace(fileEntry.name, newName);
            }
        }).then(function(name) {
            return $mmSharedFiles.storeFileInSite(fileEntry, name, siteId).finally(function() {
                $mmSharedFiles.deleteInboxFile(fileEntry);
                $mmUtil.showModal(undefined, $translate.instant('mm.sharedfiles.successstorefile'));
            }).catch(function(err) {
                $mmUtil.showErrorModal(err || 'Error moving file.');
                return $q.reject();
            });
        });
    };

    return self;
});
<commit_msg>MOBILE-1606 sharedfiles: Don't treat new files if one is pending<commit_after>// (C) Copyright 2015 Martin Dougiamas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

angular.module('mm.core.sharedfiles')

.factory('$mmSharedFilesHelper', function($mmSharedFiles, $mmUtil, $log, $mmApp, $mmSitesManager, $mmFS, $rootScope, $q,
            $ionicModal, $state, $translate) {

    $log = $log.getInstance('$mmSharedFilesHelper');

    var self = {};

    /**
     * Ask a user if he wants to replace a file (using originalName) or rename it (using newName).
     *
     * @module mm.core.sharedfiles
     * @ngdoc method
     * @name $mmSharedFilesHelper#askRenameReplace
     * @param  {String} originalName Original name.
     * @param  {String} newName      New name.
     * @return {Promise}             Promise resolved with the name to use when the user chooses. Rejected if user cancels.
     */
    self.askRenameReplace = function(originalName, newName) {
        var scope = $rootScope.$new();
        scope.originalName = originalName;
        scope.newName = newName;

        return $ionicModal.fromTemplateUrl('core/components/sharedfiles/templates/renamereplace.html', {
            scope: scope,
            animation: 'slide-in-up'
        }).then(function(modal) {
            var deferred = $q.defer();

            scope.modal = modal;
            modal.show();

            scope.click = function(name) {
                close();
                deferred.resolve(name);
            };

            scope.closeModal = function() {
                close();
                deferred.reject();
            };

            function close() {
                modal.remove();
                scope.$destroy();
            }

            return deferred.promise;
        });
    };

    /**
     * Go to the choose site view.
     *
     * @module mm.core.sharedfiles
     * @ngdoc method
     * @name $mmSharedFilesHelper#goToChooseSite
     * @param  {String} filePath File path to send to the view.
     * @return {Promise}         Promise resolved when state changed.
     */
    self.goToChooseSite = function(filePath) {
        var parentState = $state.$current.name.split('.')[0];
        return $state.go(parentState + '.sharedfiles-choose-site', {filepath: filePath});
    };

    /**
     * Checks if there is a new file received in iOS and move it to the shared folder of current site.
     * If more than one site is found, the user will have to choose the site where to store it in.
     * If more than one file is found, treat only the first one.
     *
     * @module mm.core.sharedfiles
     * @ngdoc method
     * @name $mmSharedFilesHelper#searchIOSNewSharedFiles
     * @return {Promise} Promise resolved when done.
     */
    self.searchIOSNewSharedFiles = function() {
        return $mmApp.ready().then(function() {
            if ($state.$current.name == 'site.sharedfiles-choose-site') {
                // We're already treating a shared file. Abort.
                return $q.reject();
            }

            return $mmSharedFiles.checkIOSNewFiles().then(function(fileEntry) {
                return $mmSitesManager.getSitesIds().then(function(siteIds) {
                    if (!siteIds.length) {
                        // No sites stored, show error and delete the file.
                        $mmUtil.showErrorModal('mm.sharedfiles.errorreceivefilenosites', true);
                        $mmSharedFiles.deleteInboxFile(fileEntry);
                    } else if (siteIds.length == 1) {
                        self.storeSharedFileInSite(fileEntry, siteIds[0]);
                    } else {
                        self.goToChooseSite(fileEntry.fullPath);
                    }
                });
            });
        });
    };

    /**
     * Store a shared file in a site's shared files folder.
     *
     * @module mm.core.sharedfiles
     * @ngdoc method
     * @name $mmSharedFilesHelper#storeSharedFileInSite
     * @param  {Object} fileEntry Shared file entry.
     * @param  {String} [siteId]  Site ID. If not defined, current site.
     * @return {promise}          Promise resolved when done.
     */
    self.storeSharedFileInSite = function(fileEntry, siteId) {
        siteId = siteId || $mmSite.getId();

        // First of all check if there's already a file with the same name in the shared files folder.
        return $mmSharedFiles.getSiteSharedFiles(siteId).then(function(entries) {
            var files = {};

            // Index the files by name.
            angular.forEach(entries, function(entry) {
                files[entry.name] = entry;
            });

            if (typeof files[fileEntry.name] == 'undefined') {
                // No file with the same name. Use the original file name.
                return fileEntry.name;
            } else {
                // Repeated name. Add a number until we find a free name.
                var newName,
                    number = 1,
                    extension = $mmFS.getFileExtension(fileEntry.name),
                    nameWithoutExtension = fileEntry.name.substr(0, fileEntry.name.length - extension.length - 1);

                do {
                    newName = nameWithoutExtension + '(' + number + ').' + extension;
                    number++;
                } while (typeof files[newName] != 'undefined');

                // Ask the user what he wants to do.
                return self.askRenameReplace(fileEntry.name, newName);
            }
        }).then(function(name) {
            return $mmSharedFiles.storeFileInSite(fileEntry, name, siteId).finally(function() {
                $mmSharedFiles.deleteInboxFile(fileEntry);
                $mmUtil.showModal(undefined, $translate.instant('mm.sharedfiles.successstorefile'));
            }).catch(function(err) {
                $mmUtil.showErrorModal(err || 'Error moving file.');
                return $q.reject();
            });
        });
    };

    return self;
});
<|endoftext|>


<commit_before>/**
 * @fileoverview Test utilities.
 */

goog.module('googlejs.testUtils');

const eslint = /** @type {!ESLint.Module} */ (require('eslint'));

/**
 * Creates a function thats takes a string of source code and returns the result
 * of executing nodeFunction on the first nodeType in the parsed source code.
 * @param {string} nodeType A node type like 'VariableDeclaration'.
 * @param {function(!AST.Node):*} nodeFunction Function to call on the node
 *     type.
 * @return {function(string):*}
 */
function eslintVerifier(nodeType, nodeFunction) {
  return (code) => eslintVerify(nodeType, nodeFunction, code);
}

/**
 * Executes the provided function on the first parsed node of nodeType and
 * returns the result.
 * @param {string} nodeType A node type like 'VariableDeclaration'.
 * @param {function(!AST.Node)} nodeFunction Function to call on the node type.
 * @param {string} code The source code to parse.
 * @return {*}
 */
function eslintVerify(nodeType, nodeFunction, code) {
  const filename = 'test.js';
  const eslintOptions = {
    parserOptions: {ecmaVersion: 6},
    rules: {},
  };
  let result;
  eslint.linter.reset();
  eslint.linter.once(nodeType, (node) => {
    result = nodeFunction(node);
  });
  eslint.linter.verify(code, eslintOptions, filename, true);
  return result;
}

exports = {
  eslintVerifier,
  eslintVerify,
};
<commit_msg>Fix unknown types<commit_after>/**
 * @fileoverview Test utilities.
 */

goog.module('googlejs.testUtils');

const eslint = /** @type {!ESLint.Module} */ (require('eslint'));

/**
 * Creates a function thats takes a string of source code and returns the result
 * of executing nodeFunction on the first nodeType in the parsed source code.
 * @param {string} nodeType A node type like 'VariableDeclaration'.
 * @param {function(!AST.Node):*} nodeFunction Function to call on the node
 *     type.
 * @return {function(string):*}
 */
function eslintVerifier(nodeType, nodeFunction) {
  return (code) => eslintVerify(nodeType, nodeFunction, code);
}

/**
 * Executes the provided function on the first parsed node of nodeType and
 * returns the result.
 * @param {string} nodeType A node type like 'VariableDeclaration'.
 * @param {function(!AST.Node):*} nodeFunction Function to call on the node
 *     type.
 * @param {string} code The source code to parse.
 * @return {*}
 */
function eslintVerify(nodeType, nodeFunction, code) {
  const filename = 'test.js';
  const eslintOptions = {
    parserOptions: {ecmaVersion: 6},
    rules: {},
  };
  /** @type {*} */
  let result;
  eslint.linter.reset();
  eslint.linter.once(nodeType, (node) => {
    result = nodeFunction(node);
  });
  eslint.linter.verify(code, eslintOptions, filename, true);
  return result;
}

exports = {
  eslintVerifier,
  eslintVerify,
};
<|endoftext|>


<commit_before>Ext.onReady(function()
{
  History = function()
  {

    // need this pointer for event-function
    var finalThis = this;

    var updateDropDownMenu = function()
    {
      var items = finalThis.splitButton.menu.items;
      const
      MAX_MENU_ITEMS = 5;

      // only insert if, store has really stored a new element
      if ((items === undefined) || (store.getCount() > items.getCount()))
      {
        finalThis.splitButton.menu.insert(0, {
          text : (store.getAt(0)).data['query'],
          handler : function(b, e)
          {
            Ext.getCmp('queryAnnisQL').setValue(b.text);
          }
        });
      } else
      {
        /**
         * if this query is already in the menu, the menu is cleared. This might
         * be inefficient for big histories.
         *
         */
        finalThis.splitButton.menu.removeAll();
        var recordsArray = store.getRange([ 0 ], [ MAX_MENU_ITEMS - 1 ]);
        // count the other way around for ascending sorted menu
        for ( var i = recordsArray.length - 1; i >= 0; i--)
        {
          finalThis.splitButton.menu.insert(0, {
            text : recordsArray[i].data['query'],
            handler : function(b, e)
            {
              Ext.getCmp('queryAnnisQL').setValue(b.text);
            }
          });
        }
      }

      // delete least added element
      if (items !== undefined && items.getCount() > MAX_MENU_ITEMS)
        finalThis.splitButton.menu.remove(items.last());

    };

    // initiate GridView for all queries
    var store = new Ext.data.ArrayStore({
      fields : [ {
        name : 'query',
        name : 'citation'
      } ],
      listeners : {
        'add' : updateDropDownMenu
      }
    });

    var grid = new Ext.grid.GridPanel({
      store : store,
      columns : [ {
        header : '#',
        width : 30,
        renderer : function(value, metadata, record, rowIndex, colIndex)
        {
          return (rowIndex + 1);
        }
      }, {
        id : 'query',
        header : 'Query',
        sortable : true,
        width : 330,
        dataIndex : 'query'
      }, {
        header : "url",
        width : 30,
        dataIndex : "citation",
        renderer : function(value)
        {
          return "";
        }
      } ],
      sm : new Ext.grid.RowSelectionModel({
        singleSelect : true,
        store : store,
        listeners : {
          'rowselect' : function(row, rowIndex, record)
          {
            Ext.getCmp('queryAnnisQL').setValue(record.get('query'));
          }
        }
      }),
      viewConfig : {
        rowOverCls : 'history-hover'
      },
      stripeRows : true,
      width : 400,
      height : 300
    });

    // initiate window
    var win = new Ext.Window({
      autoDestroy : true,
      title : 'history',
      width : 400,
      height : 300,
      items : grid,
      closeAction : 'hide',
      stateful : true,
      stateId : 'grid',
      resizable : false
    });

    var historyWindow = function()
    {
      win.show();
      grid.getView().refresh(false);
    };

    this.update = function(lastQuery)
    {

      finalThis.splitButton.enable();

      // insert query into arraystore and use query for index
      store.insert(0, new store.recordType({
        query : lastQuery,
        citation : Citation.generate(),
      }, lastQuery));

      if (win.isVisible())
        grid.getView().refresh(false);
    };

    this.splitButton = new Ext.SplitButton({
      fieldLabel : 'History',
      text : 'Query History',
      menu : new Ext.menu.Menu(),
      listeners : {
        'click' : historyWindow
      },
      disabled : true
    });
  };
});<commit_msg>the history-window is now liquid<commit_after>Ext.onReady(function()
{
  History = function()
  {

    // need this pointer for event-function
    var finalThis = this;

    var updateDropDownMenu = function()
    {
      var items = finalThis.splitButton.menu.items;
      const
      MAX_MENU_ITEMS = 5;

      // only insert if, store has really stored a new element
      if ((items === undefined) || (store.getCount() > items.getCount()))
      {
        finalThis.splitButton.menu.insert(0, {
          text : (store.getAt(0)).data['query'],
          handler : function(b, e)
          {
            Ext.getCmp('queryAnnisQL').setValue(b.text);
          }
        });
      } else
      {
        /**
         * if this query is already in the menu, the menu is cleared. This might
         * be inefficient for big histories.
         *
         */
        finalThis.splitButton.menu.removeAll();
        var recordsArray = store.getRange([ 0 ], [ MAX_MENU_ITEMS - 1 ]);
        // count the other way around for ascending sorted menu
        for ( var i = recordsArray.length - 1; i >= 0; i--)
        {
          finalThis.splitButton.menu.insert(0, {
            text : recordsArray[i].data['query'],
            handler : function(b, e)
            {
              Ext.getCmp('queryAnnisQL').setValue(b.text);
            }
          });
        }
      }

      // delete least added element
      if (items !== undefined && items.getCount() > MAX_MENU_ITEMS)
        finalThis.splitButton.menu.remove(items.last());

    };

    // initiate GridView for all queries
    var store = new Ext.data.ArrayStore({
      fields : [ {
        name : 'query',
        name : 'citation'
      } ],
      listeners : {
        'add' : updateDropDownMenu
      }
    });

    var grid = new Ext.grid.GridPanel({
      store : store,
      columns : [ {
        header : '#',
        width : 30,
        fixed: true,
        renderer : function(value, metadata, record, rowIndex, colIndex)
        {
          return (rowIndex + 1);
        }
      }, {
        id : 'query',
        header : 'Query',
        sortable : true,
        dataIndex : 'query'
      }, {
        header : "url",
        width : 30,
        fixed: true,
        dataIndex : "citation",
        renderer : function(value)
        {
          return "";
        }
      } ],
      sm : new Ext.grid.RowSelectionModel({
        singleSelect : true,
        store : store,
        listeners : {
          'rowselect' : function(row, rowIndex, record)
          {
            Ext.getCmp('queryAnnisQL').setValue(record.get('query'));
          }
        }
      }),
      viewConfig : {
        rowOverCls : 'history-hover',
        forceFit:true,
        autoFill: true
      },
      loadMask: true,
      autoHeight: true,
      autoWidth: true,
      stripeRows : true
    });

    // initiate window
    var win = new Ext.Window({
      autoDestroy : true,
      title : 'history',
      width : 400,
      height : 300,
      items : grid,
      closeAction : 'hide',
      stateful : true,
      stateId : 'grid',
      layout : 'fit',
      autoScroll : true
    });

    var historyWindow = function()
    {
      win.show();
      grid.getView().refresh(false);
    };

    this.update = function(lastQuery)
    {

      finalThis.splitButton.enable();

      // insert query into arraystore and use query for index
      store.insert(0, new store.recordType({
        query : lastQuery,
        citation : Citation.generate(),
      }, lastQuery));

      if (win.isVisible())
        grid.getView().refresh(false);
    };

    this.splitButton = new Ext.SplitButton({
      fieldLabel : 'History',
      text : 'Query History',
      menu : new Ext.menu.Menu(),
      listeners : {
        'click' : historyWindow
      },
      disabled : true
    });
  };
});<|endoftext|>


<commit_before>---
---
// FAB Button
// ===================
(function() {

  // Styling
  // temporary until new css released across all profiles
  var isMobile = window.matchMedia('only screen and (max-width: 992px)').matches;
  var stylesModal = '';
  var stylesFab = '';
  if (!isMobile) {
    stylesFab = '';
  }

  // Modal
  var subject = encodeURIComponent(document.title);
  var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
  var modal = '

  email

Send to yourself or a colleague

  email

Let us know what information is useful

 hello@grantmakers.io

'

  // Feature Discovery
  var discover = '

Did you find the information you\'re looking for?

As a community project, your feedback helps us determine what information to include in profiles.

'

  // Button
  var fab = '
mail
';

  // Insert into DOM
  $('body').append(modal);
  $('.feedback-wrapper').html(stylesFab + stylesModal + fab + discover);

  // Initialize
  $('.modal').modal();
  $('.modal-trigger').modal();

  var scrollFireOptions = [
    {selector: 'footer', offset: 0, callback: function(el) {
      $('.tap-target').tapTarget('open')
    } },
  ];
  Materialize.scrollFire(scrollFireOptions);

})();
<commit_msg>Disable feature discovery on mobile<commit_after>---
---
// FAB Button
// ===================
(function() {

  // Styling
  // temporary until new css released across all profiles
  var isMobile = window.matchMedia('only screen and (max-width: 992px)').matches;
  var stylesModal = '';
  var stylesFab = '';
  if (!isMobile) {
    stylesFab = '';
  }

  // Modal
  var subject = encodeURIComponent(document.title);
  var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
  var modal = '

  email

Send to yourself or a colleague

  email

Let us know what information is useful

 hello@grantmakers.io

'

  // Feature Discovery
  var discover = '

Did you find the information you\'re looking for?

As a community project, your feedback helps us determine what information to include in profiles.

'

  // Button
  var fab = '
mail
';

  // Insert into DOM
  $('body').append(modal);
  $('.feedback-wrapper').html(stylesFab + stylesModal + fab + discover);

  // Initialize
  $('.modal').modal();
  $('.modal-trigger').modal();

  if (!isMobile) {
    var scrollFireOptions = [
      {selector: 'footer', offset: 0, callback: function(el) {
        $('.tap-target').tapTarget('open')
      } },
    ];
    Materialize.scrollFire(scrollFireOptions);
  }

})();
<|endoftext|>


<commit_before>/**
 * 按入口页面输出项目
 */
var path = require('path');
var fs = require('fs');
var shell = require('shelljs');
var utils = require('./utils');
require("consoleplusplus");
console.disableTimestamp();
var plugins = require('./plugins');
var tagExtension = require('knighkit-tag-extension');
var cwd = process.cwd();

var config = {};

if (fs.existsSync(path.resolve(cwd, './configs.js'))) {
    config = require(path.resolve(cwd, './configs.js'));
} else if (fs.existsSync(path.resolve(cwd, './kConfig/configs.js'))) {
    config = require(path.resolve(cwd, './kConfig/configs.js'));
}

var concatServerBaseUrl = '.';
var projectPublishRoot = '';

var getPageDir = function (subPage) {
    var projectPath = path.resolve(cwd, './__publish__');
    return /\/pages\/|\\pages\\/.test(subPage) ? path.join(projectPath, path.relative(path.resolve(cwd, './pages'), path.dirname(subPage)))//处于正宗的pages文件夹中，播出pages这一层，建立文件夹
        : path.join(projectPath, path.relative(cwd, path.dirname(subPage)));
};

/**
 * 创建项目输出目录
 * @param pageUrl
 */
var mkProjectDir = function () {
    var projectPath = path.resolve(cwd, './__publish__');
    projectPublishRoot = projectPath;
    if (!fs.existsSync(path.resolve(cwd, './__publish__'))) {
        fs.mkdirSync(path.resolve(cwd, './__publish__'));
    }
    fs.mkdirSync(projectPath + '/styles');
    fs.mkdirSync(projectPath + '/scripts');
    fs.mkdirSync(projectPath + '/statics');

    pageToPublish.forEach(function (subPage) {
        var dirPath = getPageDir(subPage);
        if (!fs.existsSync(dirPath)) {
            shell.mkdir('-p', dirPath);
        }
    });
};

/**
 * 发布一个项目
 * @param pageUrl 项目入口文件路径
 * @param toServer 是否上传到服务器
 */
var publishOnePage = function (pageUrl, toServer) {
    console.info('#yellow{<-----pack ' + pageUrl + '----->}:');
    var projectRoot = getPageDir(pageUrl);
    var pageName = path.basename(path.basename(pageUrl, '.html'), '.htm');
    var htmlCode = analyzeHtml(pageUrl, path.resolve(cwd, './__publish__'), pageName, toServer);
    var minify = require('html-minifier').minify;
    if (!/^<\?xml.*\?>/.test(htmlCode)) {
        htmlCode = minify(htmlCode, config.htmlmin || {});
    }
    console.info('#yellow{minify ' + pageUrl + ' done}\n\n');
    fs.writeFileSync(projectRoot + '/' + pageName + '.htm', htmlCode);
    console.info('#yellow{<-----pack ' + pageUrl + ' done----->}\n\n');
};

/**
 * 处理匹配的类型
 * @param type
 * @param args
 * @param htmlpath
 * @param projectRoot
 * @param pageName
 * @returns {*}
 */
var handleMatch = function (type, args, htmlpath, projectRoot, pageName) {
    var plugin = plugins.use(args);
    if (plugin[type] !== undefined) {
        return plugin[type](args[0], htmlpath, projectRoot, pageName, concatServerBaseUrl, projectPublishRoot);
    } else {
        return args[0];
    }
};

/**
 * 获取<script ... src="path"></script>
 * 获取<img ... src="path"></script>
 * 获取<link ... rel="stylesheet" href="path" />
 * @param htmlpath html文件的路径
 * @param projectRoot 项目根目录
 * @param pageName 页面文件名
 * @param toServer  是否上传到服务器，当不上传到服务器，只在本地测试时，需要把include的页面也直接静态的合并到页面代码中，否则不支持include语法
 *
 */
var analyzeHtml = function (htmlpath, projectRoot, pageName, toServer) {
    var content = tagExtension.puz(path.resolve(cwd, htmlpath));
    if (!toServer) {
        content = tagExtension.include(path.resolve(cwd, htmlpath), content);
    }
    var reg = new RegExp(plugins.regsExceptScript, 'ig');
    plugins.reset();

    //预处理某些css等资源
    content.replace(reg, function (m) {
        handleMatch('preReplace', arguments, htmlpath, projectRoot, pageName);//replace前做的准备
    });

    //单独处理script标签，因为script中同时包含页面所需的css和其他静态资源
    content = content.replace(utils.regs['script'], function (m) {
        return handleMatch('replace', arguments, htmlpath, projectRoot, pageName);
    });

    return content.replace(reg, function (m) {
        return handleMatch('replace', arguments, htmlpath, projectRoot, pageName);
    });
};

var isLegalFile = function (url) {
    var pass = false;
    var filters = config.htmlPublishFilter || [/\.htm$|\.html$/];
    for (var idx = 0; idx < filters.length; idx++) {
        if (filters[idx].test(url)) {
            pass = true;
            break;
        }
    }
    return pass;
};

/**
 * 发布所有的页面
 * @param dir
 */
var pageToPublish = [];
var collectAllPages = function (dir) {
    var stat = fs.statSync(dir);
    if (stat.isDirectory()) {
        var files = fs.readdirSync(dir);
        files.forEach(function (value) {
            var realPath = path.join(dir, value);
            var stat = fs.statSync(realPath);
            if (stat.isDirectory() && value !== 'src' && value !== 'kConfig' && value !== 'lib' && value !== 'output') {
                collectAllPages(realPath);
            } else if (isLegalFile(realPath)) {
                pageToPublish.push(realPath);
            }
        });
    } else {
        pageToPublish.push(dir);
    }
};

/**
 * 输出项目
 * @param pageUrl 项目入口页面
 */
exports.publish = function (pageUrl) {
    pageToPublish = [];//重置
    shell.rm('-rf', path.resolve(cwd, './__publish__'));//清除原生成文件
    var toServer = /.*_toserver$/g.test(pageUrl); //是否上传到服务器
    if (toServer) { //pageUrl 以 _toserver结尾，表示要发布到服务端，包括cdn，加上配置文件中的serverUrl
        concatServerBaseUrl = config.serverUrl;
        if (concatServerBaseUrl === undefined) {
            console.error('Please check out your config file, and set the attribute "serverUrl"!');
            return;
        }
        pageUrl = pageUrl.replace(/_toserver$/g, '');//去掉 _toserver 后缀
    }

    collectAllPages(path.resolve(cwd, pageUrl || ""));

    mkProjectDir(pageUrl);

    pageToPublish.forEach(function (value) {
        publishOnePage(value, toServer);
    });

    var pageName = path.basename(path.basename(pageUrl, '.html'), '.htm');
    if (pageName === 'undefined' || pageName === 'pages') {
        pageName = '';
    }
    //拷贝需要的静态资源文件
    if (Array.isArray(config.staticResource)) {
        config.staticResource.forEach(function (val) {
            shell.cp('-Rf',
                path.resolve(cwd, val.source),
                path.resolve(cwd + '/__publish__/' + (pageName || ''), val.target));  //styles
        });
    }
};

exports.getConfig = function () {
    return config;
};<commit_msg>MOD:  本地测试解析标签支持嵌套<commit_after>/**
 * 按入口页面输出项目
 */
var path = require('path');
var fs = require('fs');
var shell = require('shelljs');
var utils = require('./utils');
require("consoleplusplus");
console.disableTimestamp();
var plugins = require('./plugins');
var tagExtension = require('knighkit-tag-extension');
var cwd = process.cwd();

var config = {};

if (fs.existsSync(path.resolve(cwd, './configs.js'))) {
    config = require(path.resolve(cwd, './configs.js'));
} else if (fs.existsSync(path.resolve(cwd, './kConfig/configs.js'))) {
    config = require(path.resolve(cwd, './kConfig/configs.js'));
}

var concatServerBaseUrl = '.';
var projectPublishRoot = '';

var getPageDir = function (subPage) {
    var projectPath = path.resolve(cwd, './__publish__');
    return /\/pages\/|\\pages\\/.test(subPage) ? path.join(projectPath, path.relative(path.resolve(cwd, './pages'), path.dirname(subPage)))//处于正宗的pages文件夹中，播出pages这一层，建立文件夹
        : path.join(projectPath, path.relative(cwd, path.dirname(subPage)));
};

/**
 * 创建项目输出目录
 * @param pageUrl
 */
var mkProjectDir = function () {
    var projectPath = path.resolve(cwd, './__publish__');
    projectPublishRoot = projectPath;
    if (!fs.existsSync(path.resolve(cwd, './__publish__'))) {
        fs.mkdirSync(path.resolve(cwd, './__publish__'));
    }
    fs.mkdirSync(projectPath + '/styles');
    fs.mkdirSync(projectPath + '/scripts');
    fs.mkdirSync(projectPath + '/statics');

    pageToPublish.forEach(function (subPage) {
        var dirPath = getPageDir(subPage);
        if (!fs.existsSync(dirPath)) {
            shell.mkdir('-p', dirPath);
        }
    });
};

/**
 * 发布一个项目
 * @param pageUrl 项目入口文件路径
 * @param toServer 是否上传到服务器
 */
var publishOnePage = function (pageUrl, toServer) {
    console.info('#yellow{<-----pack ' + pageUrl + '----->}:');
    var projectRoot = getPageDir(pageUrl);
    var pageName = path.basename(path.basename(pageUrl, '.html'), '.htm');
    var htmlCode = analyzeHtml(pageUrl, path.resolve(cwd, './__publish__'), pageName, toServer);
    var minify = require('html-minifier').minify;
    if (!/^<\?xml.*\?>/.test(htmlCode)) {
        htmlCode = minify(htmlCode, config.htmlmin || {});
    }
    console.info('#yellow{minify ' + pageUrl + ' done}\n\n');
    fs.writeFileSync(projectRoot + '/' + pageName + '.htm', htmlCode);
    console.info('#yellow{<-----pack ' + pageUrl + ' done----->}\n\n');
};

/**
 * 处理匹配的类型
 * @param type
 * @param args
 * @param htmlpath
 * @param projectRoot
 * @param pageName
 * @returns {*}
 */
var handleMatch = function (type, args, htmlpath, projectRoot, pageName) {
    var plugin = plugins.use(args);
    if (plugin[type] !== undefined) {
        return plugin[type](args[0], htmlpath, projectRoot, pageName, concatServerBaseUrl, projectPublishRoot);
    } else {
        return args[0];
    }
};

/**
 * 获取<script ... src="path"></script>
 * 获取<img ... src="path"></script>
 * 获取<link ... rel="stylesheet" href="path" />
 * @param htmlpath html文件的路径
 * @param projectRoot 项目根目录
 * @param pageName 页面文件名
 * @param toServer  是否上传到服务器，当不上传到服务器，只在本地测试时，需要把include的页面也直接静态的合并到页面代码中，否则不支持include语法
 *
 */
var analyzeHtml = function (htmlpath, projectRoot, pageName, toServer) {
    var content = tagExtension.puz(path.resolve(cwd, htmlpath));
    if (!toServer) {
        content = tagExtension.multiTag(path.resolve(cwd, htmlpath));
    }
    var reg = new RegExp(plugins.regsExceptScript, 'ig');
    plugins.reset();

    //预处理某些css等资源
    content.replace(reg, function (m) {
        handleMatch('preReplace', arguments, htmlpath, projectRoot, pageName);//replace前做的准备
    });

    //单独处理script标签，因为script中同时包含页面所需的css和其他静态资源
    content = content.replace(utils.regs['script'], function (m) {
        return handleMatch('replace', arguments, htmlpath, projectRoot, pageName);
    });

    return content.replace(reg, function (m) {
        return handleMatch('replace', arguments, htmlpath, projectRoot, pageName);
    });
};

var isLegalFile = function (url) {
    var pass = false;
    var filters = config.htmlPublishFilter || [/\.htm$|\.html$/];
    for (var idx = 0; idx < filters.length; idx++) {
        if (filters[idx].test(url)) {
            pass = true;
            break;
        }
    }
    return pass;
};

/**
 * 发布所有的页面
 * @param dir
 */
var pageToPublish = [];
var collectAllPages = function (dir) {
    var stat = fs.statSync(dir);
    if (stat.isDirectory()) {
        var files = fs.readdirSync(dir);
        files.forEach(function (value) {
            var realPath = path.join(dir, value);
            var stat = fs.statSync(realPath);
            if (stat.isDirectory() && value !== 'src' && value !== 'kConfig' && value !== 'lib' && value !== 'output') {
                collectAllPages(realPath);
            } else if (isLegalFile(realPath)) {
                pageToPublish.push(realPath);
            }
        });
    } else {
        pageToPublish.push(dir);
    }
};

/**
 * 输出项目
 * @param pageUrl 项目入口页面
 */
exports.publish = function (pageUrl) {
    pageToPublish = [];//重置
    shell.rm('-rf', path.resolve(cwd, './__publish__'));//清除原生成文件
    var toServer = /.*_toserver$/g.test(pageUrl); //是否上传到服务器
    if (toServer) { //pageUrl 以 _toserver结尾，表示要发布到服务端，包括cdn，加上配置文件中的serverUrl
        concatServerBaseUrl = config.serverUrl;
        if (concatServerBaseUrl === undefined) {
            console.error('Please check out your config file, and set the attribute "serverUrl"!');
            return;
        }
        pageUrl = pageUrl.replace(/_toserver$/g, '');//去掉 _toserver 后缀
    }

    collectAllPages(path.resolve(cwd, pageUrl || ""));

    mkProjectDir(pageUrl);

    pageToPublish.forEach(function (value) {
        publishOnePage(value, toServer);
    });

    var pageName = path.basename(path.basename(pageUrl, '.html'), '.htm');
    if (pageName === 'undefined' || pageName === 'pages') {
        pageName = '';
    }
    //拷贝需要的静态资源文件
    if (Array.isArray(config.staticResource)) {
        config.staticResource.forEach(function (val) {
            shell.cp('-Rf',
                path.resolve(cwd, val.source),
                path.resolve(cwd + '/__publish__/' + (pageName || ''), val.target));  //styles
        });
    }
};

exports.getConfig = function () {
    return config;
};<|endoftext|>


<commit_before>'use strict';

//process.env.DEBUG = "mediasoup*";

const os = require('os');
const ip = require('ip');
const fs = require('fs');
const net = require('net');
const url = require('url');
const udid = require('udid');
const util = require('util');
const path = require('path');
const rtsp = require('rtsp-stream');
const dgram = require('dgram');
const https = require('https');
const express = require('express');
const Promise = require('bluebird');
const socketIO = require('socket.io');
const child_process = require('child_process');
const sdp_transform = require('sdp-transform');

const mediasoup = require('mediasoup');
const RTCPeerConnection = mediasoup.webrtc.RTCPeerConnection;
const RTCSessionDescription = mediasoup.webrtc.RTCSessionDescription;
const roomOptions = require('./data/options').roomOptions;

const OutputTypes = {
	RTMP: 1,
	MP4: 3
};

class Room {

	constructor(mediaServer, name){
		const d = new Date();
		this.id = udid('y' + name + d.getTime());
		this.name = name;
		this.mediaServer = mediaServer;
	}

	init() {
		let This = this;

		return new Promise((resolve, reject) => {
			This.mediaServer.createRoom(roomOptions)
    	    .then((mediaRoom) => {
				This.mediaRoom = mediaRoom;
				resolve(This);
    	    })
			.catch((err) => reject(err));
		});
	}

}

const max32 = Math.pow(2, 32) - 1;

class Connection {
	constructor(server, socket){
		this.server = server;
		this.socket = socket;
		this.peerconnection = null;

		this.id = socket.id;
//		this.id = Math.floor(Math.random() * max32).toString();
		this.sdp = null;
		this.roomId = null;
		this.mediaPeer = null;

		let This = this;

		server.addConnection(this);

		// socket.io
		socket.on('disconnect', () => {
			This.closePeerConnection();
			server.removeConnection(This.id);
		});

		socket.on('error', (err) => {
			console.error('ERROR:', err);
		});

		socket.on('list', () => {
			This.debug(`Receive [${This.id}] [list]`);
			This.send('list', This.server.getRoomsList());
		});

		socket.on('create-room', (name) => {
			This.debug(`Receive [${This.id}] [create-room] name [${name}]`);
			This.server.addRoom(name).
			then((room) => {
				This.send('room-created', {
					id: room.id,
					name: room.name
				});
			});
		});

		socket.on('join', (message) => {
			This.debug(`Receive [${This.id}] [join] room id [${message.roomId}]`);
			let room = This.server.getRoom(message.roomId);
			if(room) {
    			socket.join(message.roomId);
    			This.roomId = message.roomId;
    			This.handleOffer(message.sdp, message.planb);
			}
			else {
				This.send('error', 'Room not found');
			}
		});

		socket.on('joined', (answer) => {
			This.debug(`Receive [${This.id}] [joined]`);
			This.handleAnswer(answer);
		});

		socket.on('quit', () => {
			This.debug(`Receive [${This.id}] [quit]`);
			This.closePeerConnection();
		});
	}

	debug(message) {
		this.server.debug(message);
	}

	send(type, data) {
		this.debug(`Sending [${this.id}], type: ${type}: ` + util.inspect(data));
		this.socket.emit(type, data);
	};

	sendRoom(type, data) {
		this.debug(`Sending [${this.id}], type: ${type}: ` + util.inspect(data));
		this.server.io.sockets.in(this.roomId).emit(type, data);
	};

	closePeerConnection() {
		if(this.peerconnection) {
			this.peerconnection.close();
			this.peerconnection = null;
		}
	}

	handleOffer(sdp, usePlanB) {
		let This = this;

		let room = this.server.getRoom(this.roomId);
		this.mediaPeer = room.mediaRoom.Peer(this.id);
		this.peerconnection = new RTCPeerConnection({
			peer: this.mediaPeer,
			usePlanB: usePlanB
		});
		let peerconnection = this.peerconnection;
		peerconnection.on('close', function(err) {
			if(err) {
				console.error(`PeerConnection [${This.id}] closed,	err: ${err}`);
			}
			else {
				This.debug(`PeerConnection [${This.id}] closed`);
			}
		});
		peerconnection.on('signalingstatechange', function() {
			This.debug(`PeerConnection [${This.id}] signaling state changed,	state: ${peerconnection.signalingState}`);
		});

		// Set the remote SDP offer
		peerconnection.setCapabilities(sdp)
		.then(() => {
			console.log('after setCapabilities');
			This.sendOffer();
		});

		// Handle 'negotiationneeded' event
		peerconnection.on('negotiationneeded', () => {
			This.debug(`PeerConnection [${This.id}] negotiation needed`);
			This.sendOffer();
		});
		peerconnection.on('leave', () => {
			This.debug(`PeerConnection [${This.id}] leaves`);
			This.closePeerConnection();
		});
	}

	handleAnswer(answer) {
		let This = this;

		this.peerconnection.setRemoteDescription(answer)
		.then(() => {
			This.sendStream();
		});
	}

	sendOffer() {
		let This = this;

		This.peerconnection.createOffer()
		.then((desc) => {
			return This.peerconnection.setLocalDescription(desc);
		})
		.then(() => {
			let sessionDescription = This.peerconnection.localDescription;
			This.send(sessionDescription.type, sessionDescription.sdp);
		})
        .catch((err) => {
        	console.error(err);
        	This.peerconnection.reset();
        });
	}

	//TODO - execute the ffmpeg on remote machine
	ffmpeg(input) {
		let args = [
//			'-loglevel', 'debug',
			'-analyzeduration', '2147483647',
			'-probesize', '2147483647',
			'-protocol_whitelist', 'file,crypto,tcp,udp,rtp',
			'-i', input,
		];

		args.push('-vcodec', 'copy');
		args.push('-acodec', 'aac');
		args.push('-shortest');

		if(this.server.options.outputType === OutputTypes.RTMP) {
			args.push('-f', 'flv');
			args.push(this.server.options.rtmpURL + this.id);
		}
		else if(this.server.options.outputType === OutputTypes.MP4) {
			let ext = 'mp4';
			let outputFilePath = this.server.options.recordedMediaPath +	`/${this.id}.${ext}`;
			args.push('-y');
			args.push(outputFilePath);
		}

		let ffmpeg = this.server.options.ffmpegPath;
		let command = ffmpeg + ' ' + args.join(' ');
		console.log('Executing: ' + command);
		return child_process.spawn(ffmpeg, args);
	}

	//TODO - execute the vlc on remote machine
	vlc(input) {

		// cvlc -vvv --play-and-exit --sout-ffmpeg-strict=-2 --sout "#transcode{acodec=mp4a,ab=128,channels=2,samplerate=44100}:std{access=file,mux=mp4,dst=output2.mp4}" rtsp://dev-hudson10.dev.kaltura.com:5000/FkPeypd8i2vHvGq6AAAB.sdp

		let args = [
			'-vvv',
			'--play-and-exit',
			'--sout-ffmpeg-strict=-2',
			'--audio-desync=-2000',
//			'--no-sout-display',
//			'--sout-keep',
			'--sout-mux-caching=4096', // 2147483647
//			'--no-sout-smem-time-sync',
//			'--packetizer-mpegvideo-sync-iframe',
//			'--clock-synchro=1',
		];

//		let transcode = 'transcode{acodec=mp4a,ab=128,channels=2,samplerate=44100}';
		let transcode = 'transcode{acodec=mp4a,samplerate=44100}';
		if(this.server.options.outputType === OutputTypes.RTMP) {
//			args.push(`--sout=${transcode}:rtmp{url=${this.server.options.rtmpURL},name=${this.id}}`);
			args.push(`--sout=#${transcode}:std{access=rtmp,mux=ffmpeg{mux=flv},dst=${this.server.options.rtmpURL}${this.id}}`);
		}
		else if(this.server.options.outputType === OutputTypes.MP4) {
			let outputFilePath = this.server.options.recordedMediaPath +	`/${this.id}.mp4`;
			args.push(`--sout=#${transcode}:std{access=file,mux=mp4,dst=${outputFilePath}}`);
//			args.push(`--sout=#std{access=file,mux=mp4,dst=${outputFilePath}}`);
		}

		args.push(input);

		let vlc = this.server.options.vlcPath;
		let command = vlc + ' ' + args.join(' ');
		console.log('Executing: ' + command);
		return child_process.spawn(vlc, args);
	}

	forwardStream(sdp) {

		let input;
		if(this.server.options.rtspPort) {
			this.sdp = sdp;
			input = `rtsp://${this.server.hostname}:${this.server.options.rtspPort}/${this.id}.sdp`;
			console.log('RTSP URL: ' + input);
		}
		else {
			let sdpFilePath = this.server.options.sdpPath + `/${this.id}.sdp`;
			console.log('Saving SDP file ' + sdpFilePath);
			fs.writeFileSync(sdpFilePath, sdp);
			input = sdpFilePath;
		}

		let process = null;
		if(this.server.options.ffmpegPath) {
			process = this.ffmpeg(input);
		}
		else if(this.server.options.vlcPath) {
			process = this.vlc(input);
		}

		if(process) {
			let logPath = this.server.options.logPath + `/${this.id}.log`;
			let log = fs.createWriteStream(logPath);

    		process.stdout.on('data', (data) => {
    			let message = data.toString('utf8')
    			log.write(message);
    		});

    		process.stderr.on('data', (data) => {
    			let message = data.toString('utf8')
    			log.write(message);
    		});

    		process.on('error', (err) => {
    			console.error('Process [ffmpeg] error: ' + err);
    		});

    		process.on('exit', (code, signal) => {
    			log.end();
    			console.log(`Process [${this.id}] closed, log: ` + logPath);
    		});
		}
	}

	enableRtpPlayback(rtpReceiver) {
		let This = this;
		rtpReceiver.forwardPort = 0;

		let socket = dgram.createSocket('udp4');
		socket.on('error', (err) => {
			console.log(`UDP socket error:\n${err.stack}`);
			socket.close();
		});

		rtpReceiver.on('rtpraw', (packet) => {
			if(This.shouldPlay && rtpReceiver.forwardPort) {
//				let newPacket = new rtp.RtpPacket(packet);
//				newPacket.setSSRC(parseInt(This.id, 10));
//				socket.send(newPacket.getBuffer(), rtpReceiver.forwardPort, rtpReceiver.forwardAddress);
				socket.send(packet, rtpReceiver.forwardPort, rtpReceiver.forwardAddress);
			}
		});
		rtpReceiver.on('close', (packet) => {
			socket.close();
		});

	}

	play(){
		this.shouldPlay = true;
	}

	pause(){
		this.shouldPlay = false;
	}

	sendStream() {
		this.streams = [];

		let peer = this.peerconnection.peer;

		console.log('Build ' + peer.rtpReceivers.length + ' media descriptors');

		let description = {
			version: 0,
			origin: {
				username: 'mediasoup',
				sessionId: this.id,
				sessionVersion: 0,
				netType: 'IN',
				ipVer: 4,
				address: this.server.ip
			},
			name: this.id,
			timing: {
				start: 0,
				stop: 0
			},
			connection: {
				version: 4,
				ip: this.server.ip
			},
			media: [],
			groups: [],
//			ssrcGroups: [],
		};

		let mids = [];
//		let ssrcs = [];

		this.shouldPlay = false;
		for(let i = 0; i < peer.rtpReceivers.length; i++) {
			let rtpReceiver = peer.rtpReceivers[i];

			this.enableRtpPlayback(rtpReceiver);
			this.streams[i] = rtpReceiver;

//			let ssrc = rtpReceiver.rtpParameters.encodings[0].ssrc;
//			ssrcs.push(ssrc);

			let mid = rtpReceiver.rtpParameters.muxId;
			mids.push(mid);

			let media = {
				rtp: [],
				ext: [],
				type: rtpReceiver.kind,
//				ssrcs: [{
//					id: ssrc
//				}],
				mid: mid,
				port: 0,
				quality: 10,
//				protocol: 'RTP/SAVPF',
				protocol: 'RTP/AVP',
//				rtcpMux: 'rtcp-mux',
//				direction: 'sendrecv',
				direction: 'recvonly',
				control: 'streamid=' + i
			};

//			console.log(util.inspect(rtpReceiver.rtpParameters, {depth: 10}));

			let payloads = [];
			for(let i = 0; i < rtpReceiver.rtpParameters.codecs.length; i++){
				let codec = rtpReceiver.rtpParameters.codecs[i];
				let payload = codec.payloadType;
				media.rtp.push({
					payload: payload,
					codec: codec.name.substr(codec.name.indexOf('/') + 1),
					rate: codec.clockRate
				});
				payloads.push(payload);

				if(codec.parameters) {
					let configs = [];

					for(let parameter in codec.parameters) {
						let parameterName = parameter.split(/(?=[A-Z])/).join('-').toLowerCase();
						configs.push(parameterName + '=' + codec.parameters[parameter]);
					}

					if(configs.length) {
						if(!media.fmtp) {
							media.fmtp = [];
						}

						media.fmtp.push({
							payload: payload,
							config: configs.join(';')
						});
					}
				}

				if(codec.rtcpFeedback && codec.rtcpFeedback.length) {
					if(!media.rtcpFb) {
						media.rtcpFb = [];
					}
					for(let j = 0; j < codec.rtcpFeedback.length; j++) {
						let rtcpFeedback = codec.rtcpFeedback[j];
						media.rtcpFb.push({
							payload: payload,
							type: rtcpFeedback.type,
							subtype: rtcpFeedback.parameter,
						});
					}
				}
			}
			media.payloads = payloads.join(' ');

			for(let i = 0; i < rtpReceiver.rtpParameters.headerExtensions.length; i++){
				let headerExtension = rtpReceiver.rtpParameters.headerExtensions[i];
				media.ext.push({
					value: headerExtension.id,
					uri: headerExtension.uri
				});
			}

			description.media.push(media);
		}

		description.groups.push({
//    		type: 'BUNDLE',
			type: 'LS',
//    		type: 'FID',
//    		type: 'DDP',
			mids: mids.join(' ')
		});

//    	description.ssrcGroups.push({
//    		semantics: 'FID',
//    		ssrcs: ssrcs.join(' ')
//    	});

		let sdp = sdp_transform.write(description);
		this.forwardStream(sdp);
	}
}

class RtspServer {
	constructor(server){
		this.server = server;

		let This = this;

		this.rtspServer = net.createServer((client) => {
			console.log('RTSP client connected');

			client.on('error', (err) => {
				console.error('RTSP client error: ' + err);
			});
			client.on('end', () => {
				console.log('RTSP client disconnected');
			});
			client.on('close', () => {
				console.log('RTSP client closed');
			});

			var decoder = new rtsp.Decoder();
			var encoder = new rtsp.Encoder();

			decoder.on('request', function (request) {
				This.debug(request.method + ' ' + request.uri + ' ' + util.inspect(request.headers));

				var response = encoder.response()
				response.setHeader('CSeq', request.headers['cseq']);
				response.setHeader('Date', new Date().toGMTString());

				This.handleRequest(client, request, response);
			})

			decoder.on('error', function (err) {
				console.error(err);
				client.destroy();
			})

			client.pipe(decoder);
			encoder.pipe(client);
		});

		this.rtspServer.on('error', (err) => {
			console.log('RTSP error: ' + err);
		});
		this.rtspServer.listen(server.options.rtspPort, () => {
			console.log('RTSP server bound');
		});
	}

	handleRequest(client, request, response) {
    	let parsedUrl = url.parse(request.uri);
    	let pattern, matches;

    	if(client.connection && !client.connection.peerconnection) {
           	response.statusCode = 404; // Not found
    	}
    	else {
            switch (request.method) {
                case 'OPTIONS':
                	response.setHeader('Public', 'DESCRIBE, SETUP, TEARDOWN, PLAY', 'PAUSE');
                	break

                case 'DESCRIBE':
                	let sdp = null;

                	pattern = /^\/([^./]+)\.sdp$/i;
                	matches = pattern.exec(parsedUrl.path);
                	if(matches) {
                    	client.id = matches[1];
                    	client.connection = this.server.getConnection(client.id);
                    	if(client.connection && client.connection.peerconnection) {
                        	sdp = client.connection.sdp;
                    	}
                	}

                	pattern = /^\/([^/]+)\/([^.]+)\.sdp$/i;
                	matches = pattern.exec(parsedUrl.path);
                	if(matches) {
                    	let type = matches[1];
                    	client.id = matches[2];
                    	client.connection = this.server.getConnection(client.id);
                    	if(client.connection && client.connection.peerconnection) {
                        	sdp = client.connection.sdp[type];
                    	}
                	}

                	if(sdp) {
                    	response.setHeader('Content-Base', request.uri);
                    	response.setHeader('Content-Type', 'application/sdp');
                    	response.setHeader('Content-Length', sdp.length);
                    	response.write(sdp);
                    	break;
                	}

                   	response.statusCode = 404; // Not found
                	break

                case 'SETUP':
                	pattern = /\.sdp\/streamid=(\d+)$/i;
                	matches = pattern.exec(parsedUrl.path);
                	let streamId = parseInt(matches[1]);

                	let transport = request.headers['transport'];
                	let transportParts = transport.split(';');
                	for(let i = 0; i < transportParts.length; i++) {
                    	pattern = /^client_port=(\d+)-(\d+)$/i;
                    	matches = pattern.exec(transportParts[i]);
                		if(matches) {
                			console.dir(client.address());
                			let address = client.remoteAddress;
                			if(net.isIPv6(address)) {
                				let addressParts = address.split(':');
                				address = addressParts[addressParts.length - 1];
                				if(address === '1') {
                					address = '127.0.0.1';
                				}
                			}
                			let port = parseInt(matches[1]);
                			this.debug('Set RTP address: ' + address + ':' + port);
                			client.connection.streams[streamId].forwardAddress = address;
                			client.connection.streams[streamId].forwardPort = port;
                		}
                	}
                	response.setHeader('Transport', transport);
                	response.setHeader('Session', client.id);
                	break

                case 'PLAY':
                	client.connection.play();
                	response.setHeader('Session', client.id);
                	break

                case 'PAUSE':
                	client.connection.pause();
                	response.setHeader('Session', client.id);
                	break

                case 'TEARDOWN':
                	response.setHeader('Session', client.id);
                	break

                default:
                	response.statusCode = 501; // Not implemented
            }
    	}

        response.end();
	}

	debug(message) {
		this.server.debug(message);
	}
}

class Server {
	constructor(options){
		this.options = options;
		this.ip = ip.address();
		this.hostname = os.hostname();
		this.connections = {};

		this.start();
		this.connections = {};
		this.rooms = {};
		this.roomsList = {};

		this.mediaServer = mediasoup.Server(options);
	}

	getRoomsList() {
		return this.roomsList;
	}

	getRoom(id) {
		return this.rooms[id];
	}

	addRoom(name) {
		let room = new Room(this.mediaServer, name);
		this.rooms[room.id] = room;
		this.roomsList[room.id] = room.name;

		return room.init();
	}

	addConnection(connection) {
		this.connections[connection.id] = connection;
	}

	removeConnection(id) {
		delete this.connections[id];
	}

	getConnection(id) {
		return this.connections[id];
	}

	start() {
		this.startWebServer();
		this.startSocketIoServer();
		this.startRtspServer();
	}

	startWebServer() {
		const app = express();
		var webServerOptions = {
			key: this.options.key,
			cert: this.options.cert
		};

		let This = this;
		this.webServer = https.createServer(this.options, app).listen(this.options.webPort, function() {
			This.debug('Mediasoup demo started');
			This.debug('Open https://' + This.hostname + ':' + This.options.webPort + ' with browser');
		});
		app.use(express.static(this.options.webStaticPath));
	}

	startSocketIoServer() {
		this.io = socketIO(this.webServer);
		this.io.on('connection', function(socket){
			new Connection(server, socket);
		});
	}

	startRtspServer() {
		this.rtsp = new RtspServer(this);
	}

	debug(msg) {
		if(this.options.enableDebug) {
			console.log(msg);
		}
	}
}

const server = new Server({
	enableDebug: true,
	key: fs.readFileSync('keys/server.key'),
	cert: fs.readFileSync('keys/server.crt'),
	webPort: 3888,
	webStaticPath: 'public',

	sdpPath: path.join(__dirname, "recordings"),
	logPath: path.join(__dirname, "recordings"),
	recordedMediaPath: path.join(__dirname, "recordings"),
	rtmpURL: 'rtmp://127.0.0.1:1935/live/',
	outputType: OutputTypes.MP4,
	ffmpegPath: 'ffmpeg',
//	vlcPath: 'cvlc', // don't use vlc, the audio and video are not synchronized correctly for some reason.

	rtspPort: 5000,

    logLevel   : "debug",
    rtcIPv4    : true,
    rtcIPv6    : false,
    rtcMinPort : 40000,
    rtcMaxPort : 49999
});

<commit_msg>Refactoring code<commit_after><|endoftext|>


<commit_before>/**!
 * Droparea - Makes an easy and intuitive to upload upload files through drag and drop or select methods.
 * Copyright (c) 2015, Rogério Taques.
 *
 * @requires jQuery v1.11 or above
 * @version 1.0.6
 * @cat Plugins/Image
 * @author Rogério Taques (rogerio.taques@gmail.com)
 * @see https://github.com/rogeriotaques/droparea
 */

!function(e){"use strict";var t={url:"path/to/server/script",upload:!0,file_holder:"#file",file_preview:"#file_preview",notification_delay:5e3,accepted:".jpg|.png|.gif",file_max_size:2048,extra_data:[],success:null,i18n:{unable_to_upload:"Unable to upload at this time.
Select a file.",wrong_file_type:"Unacceptable file type!
Try: %s",wrong_file_size:"Dropped file is too big!
Max file size allowed: %s",abort:"Abort",mb:" MB",kb:" KB",percent:"% ",dismiss:"Dismiss",error:"Err: "}},a={init:function(a){return this.each(function(){var i=e(this),o=null,l=null,d=null,p={};p=e.extend({},t,a),e(p.file_holder).length&&e(p.file_preview).length&&e(p.file_holder).on("change",function(t){var a=new FileReader;a.readAsDataURL(e(this)[0].files[0]),a.onload=function(t){e(p.file_preview).animate({opacity:0},"slow",function(){e(this).attr("src",t.target.result).animate({opacity:1},"slow"),i.find(".statusbar.alert-block").fadeOut("slow",function(){e(this).remove()})})}}),i.parent().css("position",i.parent().css("position")),i.on("click",function(t){t.stopPropagation(),t.preventDefault(),e(p.file_holder).click()}).on("dragenter",function(e){e.stopPropagation(),e.preventDefault(),i.addClass("droparea-dragging")}).on("dragleave",function(e){e.stopPropagation(),e.preventDefault(),i.removeClass("droparea-dragging")}).on("dragover",function(e){e.stopPropagation(),e.preventDefault(),i.addClass("droparea-dragging")}).on("drop",function(t){if(t.preventDefault(),i.toggleClass("droparea-dropped droparea-dragging"),o=t.originalEvent.dataTransfer.files[0],!p.upload)return r(p,i,p.i18n.unable_to_upload,!0,!1),void e(p.file_holder).click();if(null!==p.accepted&&"boolean"!=typeof p.accepted&&p.accepted.indexOf(o.name.substr(o.name.lastIndexOf(".")))===-1)return void r(p,i,p.i18n.wrong_file_type.replace("%s",""+p.accepted.split("|").join(" or ")+""));if(o.size/1024>p.file_max_size)return void r(p,i,p.i18n.wrong_file_size.replace("%s",""+p.file_max_size+" "+p.i18n.kb+""));if(l=new FormData,l.append(p.file_holder.replace("#",""),o),null!==p.extra_data)for(var a in p.extra_data)e("#"+p.extra_data[a].replace("#","")).length&&l.append(p.extra_data[a].replace("#",""),e("#"+p.extra_data[a].replace("#","")).val());d=new s(i,p),d.setFileNameSize(o.name,o.size),n(l,d,i,o,p)})})}},i=0,s=function(t,a){i++,this.statusbar=e('

'),this.filename=e('

').appendTo(this.statusbar),this.size=e('

').appendTo(this.statusbar),this.progressBar=e('

').appendTo(this.statusbar),this.progressBarWidth=0,this.abort=e(''+a.i18n.abort+"
").appendTo(this.statusbar),this.statusbar.css({width:t.outerWidth(),height:t.outerHeight(),top:t.offset().top,left:t.offset().left}),t.append(this.statusbar),this.setFileNameSize=function(e,t){var i="",s=t/1024;i=parseInt(s)>1024?(s/1024).toFixed(2)+a.i18n.mb:s.toFixed(2)+a.i18n.kb,this.filename.html(e),this.size.html(i)},this.setProgress=function(e){this.progressBarWidth=e*this.progressBar.width()/100,this.progressBar.find("div").animate({width:this.progressBarWidth},10).html(e+a.i18n.percent),parseInt(e)>=100&&this.abort.hide()},this.setAbort=function(e){this.abort.on("click",function(t){t.preventDefault(),e.abort(),this.statusbar.hide()})}},r=function(t,a,i,s,r){s="undefined"==typeof s||s,r="undefined"==typeof r||r;var n=e('

'),o=(e('

').html(i).appendTo(n),e('<button class="btn dismiss"></button>').html(t.i18n.dismiss));n.css({width:a.outerWidth(),height:a.outerHeight(),top:a.offset().top,left:a.offset().left}),a.append(n),s&&o.on("click",function(t){t.stopPropagation(),t.preventDefault(),n.fadeOut("fast",function(){e(this).remove()})}).appendTo(n),r&&setTimeout(function(){n.fadeOut("fast",function(){e(this).remove()})},t.notification_delay)},n=function(t,a,i,s,r){var n=e.ajax({xhr:function(){var t=e.ajaxSettings.xhr();return t.upload&&t.upload.addEventListener("progress",function(e){var t=0,i=e.loaded||e.position,s=e.total;e.lengthComputable&&(t=Math.ceil(i/s*100)),a.setProgress(t)},!1),t},url:r.url,type:"POST",contentType:!1,processData:!1,cache:!1,data:t,success:function(t){t=e.parseJSON(t),a.setProgress(100),null!==r.success&&e.isFunction(r.success)&&r.success(t,"undefined"!=typeof t.file_name?t.file_name:null,s),i.removeClass("droparea-dropped")},error:function(e,t,i){a.progressBar.addClass("droparea-fail"),a.progressBar.find("div:first").html(r.i18n.error+i)},complete:function(t,i){setTimeout(function(){a.statusbar.fadeOut("fast",function(){e(this).remove()})},r.notification_delay)}});a.setAbort(n)};e.fn.droparea=function(t){return a[t]?a[t].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof t&&t?void e.error("Method "+t+" does not exist on jQuery.droparea()"):a.init.apply(this,arguments)}}(jQuery);<commit_msg>Extension case sensitivity fix<commit_after>/**!
 * Droparea - Makes an easy and intuitive to upload upload files through drag and drop or select methods.
 * Copyright (c) 2015, Rogério Taques.
 *
 * @requires jQuery v1.11 or above
 * @version 1.0.6
 * @cat Plugins/Image
 * @author Rogério Taques (rogerio.taques@gmail.com)
 * @see https://github.com/rogeriotaques/droparea
 */

!function(e){"use strict";var t={url:"path/to/server/script",upload:!0,file_holder:"#file",file_preview:"#file_preview",notification_delay:5e3,accepted:".jpg|.png|.gif",file_max_size:2048,extra_data:[],success:null,i18n:{unable_to_upload:"Unable to upload at this time.
Select a file.",wrong_file_type:"Unacceptable file type!
Try: %s",wrong_file_size:"Dropped file is too big!
Max file size allowed: %s",abort:"Abort",mb:" MB",kb:" KB",percent:"% ",dismiss:"Dismiss",error:"Err: "}},a={init:function(a){return this.each(function(){var i=e(this),o=null,l=null,d=null,p={};p=e.extend({},t,a),e(p.file_holder).length&&e(p.file_preview).length&&e(p.file_holder).on("change",function(t){var a=new FileReader;a.readAsDataURL(e(this)[0].files[0]),a.onload=function(t){e(p.file_preview).animate({opacity:0},"slow",function(){e(this).attr("src",t.target.result).animate({opacity:1},"slow"),i.find(".statusbar.alert-block").fadeOut("slow",function(){e(this).remove()})})}}),i.parent().css("position",i.parent().css("position")),i.on("click",function(t){t.stopPropagation(),t.preventDefault(),e(p.file_holder).click()}).on("dragenter",function(e){e.stopPropagation(),e.preventDefault(),i.addClass("droparea-dragging")}).on("dragleave",function(e){e.stopPropagation(),e.preventDefault(),i.removeClass("droparea-dragging")}).on("dragover",function(e){e.stopPropagation(),e.preventDefault(),i.addClass("droparea-dragging")}).on("drop",function(t){if(t.preventDefault(),i.toggleClass("droparea-dropped droparea-dragging"),o=t.originalEvent.dataTransfer.files[0],!p.upload)return r(p,i,p.i18n.unable_to_upload,!0,!1),void e(p.file_holder).click();if(null!==p.accepted&&"boolean"!=typeof p.accepted&&p.accepted.indexOf(o.name.substr(o.name.lastIndexOf(".")).toLowerCase())===-1)return void r(p,i,p.i18n.wrong_file_type.replace("%s",""+p.accepted.split("|").join(" or ")+""));if(o.size/1024>p.file_max_size)return void r(p,i,p.i18n.wrong_file_size.replace("%s",""+p.file_max_size+" "+p.i18n.kb+""));if(l=new FormData,l.append(p.file_holder.replace("#",""),o),null!==p.extra_data)for(var a in p.extra_data)e("#"+p.extra_data[a].replace("#","")).length&&l.append(p.extra_data[a].replace("#",""),e("#"+p.extra_data[a].replace("#","")).val());d=new s(i,p),d.setFileNameSize(o.name,o.size),n(l,d,i,o,p)})})}},i=0,s=function(t,a){i++,this.statusbar=e('

'),this.filename=e('

').appendTo(this.statusbar),this.size=e('

').appendTo(this.statusbar),this.progressBar=e('

').appendTo(this.statusbar),this.progressBarWidth=0,this.abort=e(''+a.i18n.abort+"
").appendTo(this.statusbar),this.statusbar.css({width:t.outerWidth(),height:t.outerHeight(),top:t.offset().top,left:t.offset().left}),t.append(this.statusbar),this.setFileNameSize=function(e,t){var i="",s=t/1024;i=parseInt(s)>1024?(s/1024).toFixed(2)+a.i18n.mb:s.toFixed(2)+a.i18n.kb,this.filename.html(e),this.size.html(i)},this.setProgress=function(e){this.progressBarWidth=e*this.progressBar.width()/100,this.progressBar.find("div").animate({width:this.progressBarWidth},10).html(e+a.i18n.percent),parseInt(e)>=100&&this.abort.hide()},this.setAbort=function(e){this.abort.on("click",function(t){t.preventDefault(),e.abort(),this.statusbar.hide()})}},r=function(t,a,i,s,r){s="undefined"==typeof s||s,r="undefined"==typeof r||r;var n=e('

'),o=(e('

').html(i).appendTo(n),e('<button class="btn dismiss"></button>').html(t.i18n.dismiss));n.css({width:a.outerWidth(),height:a.outerHeight(),top:a.offset().top,left:a.offset().left}),a.append(n),s&&o.on("click",function(t){t.stopPropagation(),t.preventDefault(),n.fadeOut("fast",function(){e(this).remove()})}).appendTo(n),r&&setTimeout(function(){n.fadeOut("fast",function(){e(this).remove()})},t.notification_delay)},n=function(t,a,i,s,r){var n=e.ajax({xhr:function(){var t=e.ajaxSettings.xhr();return t.upload&&t.upload.addEventListener("progress",function(e){var t=0,i=e.loaded||e.position,s=e.total;e.lengthComputable&&(t=Math.ceil(i/s*100)),a.setProgress(t)},!1),t},url:r.url,type:"POST",contentType:!1,processData:!1,cache:!1,data:t,success:function(t){t=e.parseJSON(t),a.setProgress(100),null!==r.success&&e.isFunction(r.success)&&r.success(t,"undefined"!=typeof t.file_name?t.file_name:null,s),i.removeClass("droparea-dropped")},error:function(e,t,i){a.progressBar.addClass("droparea-fail"),a.progressBar.find("div:first").html(r.i18n.error+i)},complete:function(t,i){setTimeout(function(){a.statusbar.fadeOut("fast",function(){e(this).remove()})},r.notification_delay)}});a.setAbort(n)};e.fn.droparea=function(t){return a[t]?a[t].apply(this,Array.prototype.slice.call(arguments,1)):"object"!=typeof t&&t?void e.error("Method "+t+" does not exist on jQuery.droparea()"):a.init.apply(this,arguments)}}(jQuery);
<|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = randomIntFromInterval(0, max_sleep) * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [max_time_in_seconds] [step]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

function randomIntFromInterval(min,max)
{<commit_msg>Someone poisoned the waterhole!<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(process.argv [ 5 ])
  console.info("Writing from %s to %s, with up to %s seconds between commits of %s bytes", inFile, outFile, max_sleep, step)
  var outFD = fs.openSync(outFile, 'w')
  fs.readFile(inFile, function(err,data) {
    var length = data.length
    var commit_count = Math.ceil(length / step)
    var commit_time = commit_count * max_sleep / 2
    var commit_time_hour = Math.floor(commit_time / 3600)
    var commit_time_rem = commit_time - (commit_time_hour * 3600)
    var commit_time_min = Math.floor(commit_time_rem / 60)
    var commit_time_sec = commit_time_rem - (commit_time_min * 60)
    console.info("Input file is %s Bytes, this will generate %s commits and take approximately %s hours %s minutes %s seconds", length, commit_count, commit_time_hour, commit_time_min, commit_time_sec)
    var t_offset = 0
    if (process.env.FAKETIME) {
      // 20% buffer, to reduce the likelihood of going in to the future
      t_offset = commit_time * -1.2;
      faketime(t_offset);
    }
    try {
      child_process.execFileSync('git', ['add', outFile])
    } catch (e) {
      console.error("Couldn't add %s to git: %s", outFile, e)
    }
    var counter = 0
    process.stdout.write("Queueing up the first commit...\r");
    var timeout;
    if (process.env.FAKETIME) {
      faketime(t_offset);
      timeout = 20;
    } else {
      timeout = randomIntFromInterval(0, max_sleep) * 1000
    }
    setTimeout(commit, timeout, t_offset, outFD, outFile, data, counter, length);
  })
} else {
  console.info("Usage:")
  console.info("node commit.js infile outfile [max_time_in_seconds] [step]")
}

function sleep(seconds) {
  var endTime = new Date().getTime() + (seconds * 1000);
  while (new Date().getTime() <= endTime) {;}
}

function randomIntFromInterval(min,max)
{
<|endoftext|>