<commit_before>'use strict';

import angular from 'angular';
import 'angular-ui-router';
import 'angular-animate';
import 'angular-aria';
// import 'angular-messages.min.js';

/* eslint-disable */
import ngRedux from 'ng-redux';
/* eslint-enable */
import thunk from 'redux-thunk';
import rootReducer from './reducers';

import 'angular-material';
import 'angular-material/angular-material.min.css';

if (ON_TEST) {
  require('angular-mocks');
}

const ngModule = angular
  .module('app', [
    'ui.router',
    'ngMaterial',
    'ngRedux'
  ])
/* eslint-disable */
  .config( // @ngInject
    /* eslint-enable */
    $mdThemingProvider => {
      $mdThemingProvider.theme('default')
        .primaryPalette('light-green');
    })
/* eslint-disable */
  .config( // @ngInject
    /* eslint-enable */
    $locationProvider => {
      // Enable HTML5 Location Mode
      $locationProvider.hashPrefix('!');
    })
/* eslint-disable */
  .config($ngReduxProvider => {
    /* eslint-enable */
    $ngReduxProvider.createStoreWith(rootReducer, [thunk]);
  });

// font faces and icons available site wide
// .styl files will use the font-faces
// .html file will use the icons
// webpack will url-inline them into bundle.js
import './assets/fonts/font_faces.styl';
import './assets/icons/flaticon/flaticon.css';

import commonComponents from './common/components';
commonComponents(ngModule);

import commonDirectives from './common/directives';
commonDirectives(ngModule);

import commonServices from './common/services';
commonServices(ngModule);

import home from './home';
home(ngModule);

import about from './about';
about(ngModule);

import contact from './contact';
contact(ngModule);
<commit_msg>ng-annotate redux config<commit_after>'use strict';

import angular from 'angular';
import 'angular-ui-router';
import 'angular-animate';
import 'angular-aria';
// import 'angular-messages.min.js';

/* eslint-disable */
import ngRedux from 'ng-redux';
/* eslint-enable */
import thunk from 'redux-thunk';
import rootReducer from './reducers';

import 'angular-material';
import 'angular-material/angular-material.min.css';

if (ON_TEST) {
  require('angular-mocks');
}

const ngModule = angular
  .module('app', [
    'ui.router',
    'ngMaterial',
    'ngRedux'
  ])
/* eslint-disable */
  .config( // @ngInject
    /* eslint-enable */
    $mdThemingProvider => {
      $mdThemingProvider.theme('default')
        .primaryPalette('light-green');
    })
/* eslint-disable */
  .config( // @ngInject
    /* eslint-enable */
    $locationProvider => {
      // Enable HTML5 Location Mode
      $locationProvider.hashPrefix('!');
    })
/* eslint-disable */
  .config( // @ngInject
    $ngReduxProvider => {
      /* eslint-enable */
      $ngReduxProvider.createStoreWith(rootReducer, [thunk]);
    });

// font faces and icons available site wide
// .styl files will use the font-faces
// .html file will use the icons
// webpack will url-inline them into bundle.js
import './assets/fonts/font_faces.styl';
import './assets/icons/flaticon/flaticon.css';

import commonComponents from './common/components';
commonComponents(ngModule);

import commonDirectives from './common/directives';
commonDirectives(ngModule);

import commonServices from './common/services';
commonServices(ngModule);

import home from './home';
home(ngModule);

import about from './about';
about(ngModule);

import contact from './contact';
contact(ngModule);
<|endoftext|>


<commit_before>define([
    "jQuery",
    "ace/ace",
    "ace/theme-tomorrow",
    "ace/mode-javascript",
    "utils/execute",
    "core/events",
    "core/state"
], function($, _ace, _aceTheme, _aceMode, execute, events, state){

    // Bind an exercise
    var prepareExercise = function($exercise) {
        var codeSolution = $exercise.find(".code-solution").text();
        var codeValidation = $exercise.find(".code-validation").text();
        var codeContext = $exercise.find(".code-context").text();

        var editor = ace.edit($exercise.find(".editor").get(0));
        editor.setTheme("ace/theme/tomorrow");
        editor.getSession().setUseWorker(false);
        editor.getSession().setMode("ace/mode/javascript");

        // Submit: test code
        $exercise.find(".action-submit").click(function(e) {
            e.preventDefault();

            events.trigger("exercise.submit", {type: "code"});

            execute("javascript", editor.getValue(), codeValidation, codeContext, function(err, result) {
                $exercise.toggleClass("return-error", err != null);
                $exercise.toggleClass("return-success", err == null);
                if (err) $exercise.find(".alert-danger").text(err.message || err);
            });
        });

        // Set solution
        $exercise.find(".action-solution").click(function(e) {
            e.preventDefault();

            editor.setValue(codeSolution);
            editor.gotoLine(0);
        });
    };

    // Prepare all exercise
    var init = function() {
        state.$book.find("section.exercise").each(function() {
            prepareExercise($(this));
        });
    };

    return {
        init: init,
        prepare: prepareExercise
    };
});<commit_msg>Add keyboard shortcut for submitting exercise<commit_after>define([
    "jQuery",
    "ace/ace",
    "ace/theme-tomorrow",
    "ace/mode-javascript",
    "utils/execute",
    "core/events",
    "core/state"
], function($, _ace, _aceTheme, _aceMode, execute, events, state){

    // Bind an exercise
    var prepareExercise = function($exercise) {
        var codeSolution = $exercise.find(".code-solution").text();
        var codeValidation = $exercise.find(".code-validation").text();
        var codeContext = $exercise.find(".code-context").text();

        var editor = ace.edit($exercise.find(".editor").get(0));
        editor.setTheme("ace/theme/tomorrow");
        editor.getSession().setUseWorker(false);
        editor.getSession().setMode("ace/mode/javascript");

        editor.commands.addCommand({
            name: "submit",
            bindKey: "Ctrl-Return|Cmd-Return",
            exec: function() {
                $exercise.find(".action-submit").click();
            }
        });

        // Submit: test code
        $exercise.find(".action-submit").click(function(e) {
            e.preventDefault();

            events.trigger("exercise.submit", {type: "code"});

            execute("javascript", editor.getValue(), codeValidation, codeContext, function(err, result) {
                $exercise.toggleClass("return-error", err != null);
                $exercise.toggleClass("return-success", err == null);
                if (err) $exercise.find(".alert-danger").text(err.message || err);
            });
        });

        // Set solution
        $exercise.find(".action-solution").click(function(e) {
            e.preventDefault();

            editor.setValue(codeSolution);
            editor.gotoLine(0);
        });
    };

    // Prepare all exercise
    var init = function() {
        state.$book.find("section.exercise").each(function() {
            prepareExercise($(this));
        });
    };

    return {
        init: init,
        prepare: prepareExercise
    };
});
<|endoftext|>


<commit_before>[
{"id": "align_relative_to", "title": "Aligner par rapport à ..."},
{"id": "bkgnd_color", "title": "Changer la couleur d'arrière-plan / l'opacité"},
{"id": "circle_cx", "title": "Changer la position horizontale cx du cercle"},
{"id": "circle_cy", "title": "Changer la position verticale cy du cercle"},
{"id": "circle_r", "title": "Changer le rayon du cercle"},
{"id": "connector_no_arrow", "textContent": "No arrow"},
{"id": "copyrightLabel", "textContent": "Powered by"},
{"id": "cornerRadiusLabel", "title": "Changer le rayon des coins du rectangle"},
{"id": "curve_segments", "textContent": "Courbe"},
{"id": "ellipse_cx", "title": "Changer la position horizontale cx de l'ellipse"},
{"id": "ellipse_cy", "title": "Changer la position verticale cy de l'ellipse"},
{"id": "ellipse_rx", "title": "Changer le rayon horizontal x de l'ellipse"},
{"id": "ellipse_ry", "title": "Changer le rayon vertical y de l'ellipse"},
{"id": "fill_color", "title": "Changer la couleur de remplissage"},
{"id": "fitToContent", "textContent": "Ajuster au contenu"},
{"id": "fit_to_all", "textContent": "Ajuster au contenu de tous les calques"},
{"id": "fit_to_canvas", "textContent": "Ajuster au canevas"},
{"id": "fit_to_layer_content", "textContent": "Ajuster au contenu du calque"},
{"id": "fit_to_sel", "textContent": "Ajuster à la sélection"},
{"id": "font_family", "title": "Changer la famille de police"},
{"id": "icon_large", "textContent": "Grande"},
{"id": "icon_medium", "textContent": "Moyenne"},
{"id": "icon_small", "textContent": "Petite"},
{"id": "icon_xlarge", "textContent": "Super-Grande"},
{"id": "image_height", "title": "Changer la hauteur de l'image"},
{"id": "image_opt_embed", "textContent": "Incorporer les images en tant que données (fichiers locaux)"},
{"id": "image_opt_ref", "textContent": "Utiliser la référence des images "},
{"id": "image_url", "title": "Modifier l'URL"},
{"id": "image_width", "title": "Changer la largeur de l'image"},
{"id": "includedImages", "textContent": "Images incorporées"},
{"id": "largest_object", "textContent": "Plus gros objet"},
{"id": "layer_delete", "title": "Supprimer le calque"},
{"id": "layer_down", "title": "Descendre le calque"},
{"id": "layer_new", "title": "Nouveau calque"},
{"id": "layer_rename", "title": "Renommer le calque"},
{"id": "layer_up", "title": "Monter le calque"},
{"id": "layersLabel", "textContent": "Calques :"},
{"id": "line_x1", "title": "Changer la position horizontale x de début de la ligne"},
{"id": "line_x2", "title": "Changer la position horizontale x de fin de la ligne"},
{"id": "line_y1", "title": "Changer la position verticale y de début de la ligne"},
{"id": "line_y2", "title": "Changer la position verticale y de fin de la ligne"},
{"id": "linecap_butt", "title": "Linecap: Butt"},
{"id": "linecap_round", "title": "Linecap: Round"},
{"id": "linecap_square", "title": "Linecap: Square"},
{"id": "linejoin_bevel", "title": "Linejoin: Bevel"},
{"id": "linejoin_miter", "title": "Linejoin: Miter"},
{"id": "linejoin_round", "title": "Linejoin: Round"},
{"id": "main_icon", "title": "Main Menu"},
{"id": "mode_connect", "title": "Connect two objects"},
{"id": "page", "textContent": "Page"},
{"id": "palette", "title": "Cliquer pour changer la couleur de remplissage, Shift-Clic pour changer la couleur de contour"},
{"id": "path_node_x", "title": "Changer la positon horizontale x du nœud"},
{"id": "path_node_y", "title": "Changer la position verticale y du nœud"},
{"id": "rect_height_tool", "title": "Changer la hauteur du rectangle"},
{"id": "rect_width_tool", "title": "Changer la largeur du rectangle"},
{"id": "relativeToLabel", "textContent": "Relativement à:"},
{"id": "seg_type", "title": "Changer le type du Segment"},
{"id": "selLayerLabel", "textContent": "Déplacer éléments vers:"},
{"id": "selLayerNames", "title": "Déplacer les éléments sélectionnés vers un autre calque"},
{"id": "selectedPredefined", "textContent": "Sélectionner prédéfinis:"},
{"id": "selected_objects", "textContent": "Objets sélectionnés"},
{"id": "selected_x", "title": "Changer la position horizontale X"},
{"id": "selected_y", "title": "Changer la position verticale Y"},
{"id": "smallest_object", "textContent": "Plus petit objet"},
{"id": "straight_segments", "textContent": "Droit"},
{"id": "stroke_color", "title": "Changer la couleur du contour"},
{"id": "stroke_style", "title": "Changer le style du contour"},
{"id": "stroke_width", "title": "Changer la largeur du contour"},
{"id": "svginfo_bg_note", "textContent": "Note: La toile de fond n'est pas sauvegardée avec l'image."},
{"id": "svginfo_change_background", "textContent": "Toile de fond de l'Éditeur"},
{"id": "svginfo_dim", "textContent": "Dimensions du canevas"},
{"id": "svginfo_editor_prefs", "textContent": "Préférences de l'Éditeur"},
{"id": "svginfo_height", "textContent": "Hauteur:"},
{"id": "svginfo_icons", "textContent": "Taille des icônes"},
{"id": "svginfo_image_props", "textContent": "Propriétés de l'Image"},
{"id": "svginfo_lang", "textContent": "Langue"},
{"id": "svginfo_title", "textContent": "Titre"},
{"id": "svginfo_width", "textContent": "Largeur:"},
{"id": "text", "title": "Changer le contenu du texte"},
{"id": "toggle_stroke_tools", "title": "Show/hide more stroke tools"},
{"id": "tool_add_subpath", "title": "Add sub-path"},
{"id": "tool_alignbottom", "title": "Aligner le bas des objets"},
{"id": "tool_aligncenter", "title": "Centrer verticalement"},
{"id": "tool_alignleft", "title": "Aligner les côtés gauches"},
{"id": "tool_alignmiddle", "title": "Centrer horizontalement"},
{"id": "tool_alignright", "title": "Aligner les côtés droits"},
{"id": "tool_aligntop", "title": "Aligner le haut des objets"},
{"id": "tool_angle", "title": "Changer l'angle de rotation"},
{"id": "tool_blur", "title": "Change gaussian blur value"},
{"id": "tool_bold", "title": "Texte en gras"},
{"id": "tool_circle", "title": "Cercle"},
{"id": "tool_clear", "textContent": "Nouvelle image"},
{"id": "tool_clone", "title": "Cloner l'élément"},
{"id": "tool_clone_multi", "title": "Cloner les éléments"},
{"id": "tool_delete", "title": "Supprimer l'élément"},
{"id": "tool_delete_multi", "title": "Supprimer les éléments sélectionnés"},
{"id": "tool_docprops", "textContent": "Propriétés du document"},
{"id": "tool_docprops_cancel", "textContent": "Annuler"},
{"id": "tool_docprops_save", "textContent": "OK"},
{"id": "tool_ellipse", "title": "Ellipse"},
{"id": "tool_export", "textContent": "Export as PNG"},
{"id": "tool_eyedropper", "title": "Eye Dropper Tool"},
{"id": "tool_fhellipse", "title": "Ellipse main levée"},
{"id": "tool_fhpath", "title": "Crayon à main levée"},
{"id": "tool_fhrect", "title": "Rectangle main levée"},
{"id": "tool_font_size", "title": "Taille de la police"},
{"id": "tool_group", "title": "Grouper les éléments"},
{"id": "tool_image", "title": "Outil Image"},
{"id": "tool_import", "textContent": "Import SVG"},
{"id": "tool_italic", "title": "Texte en italique"},
{"id": "tool_line", "title": "Tracer des lignes"},
{"id": "tool_move_bottom", "title": "Déplacer vers le bas"},
{"id": "tool_move_top", "title": "Déplacer vers le haut"},
{"id": "tool_node_clone", "title": "Cloner le nœud"},
{"id": "tool_node_delete", "title": "Supprimer le nœud"},
{"id": "tool_node_link", "title": "Rendre les points de contrôle solidaires"},
{"id": "tool_opacity", "title": "Changer l'opacité de l'élément"},
{"id": "tool_open", "textContent": "Ouvrir une image"},
{"id": "tool_path", "title": "Outil Chemin"},
{"id": "tool_rect", "title": "Rectangle"},
{"id": "tool_redo", "title": "Refaire l'action"},
{"id": "tool_reorient", "title": "Réorienter le chemin"},
{"id": "tool_save", "textContent": "Enregistrer l'image"},
{"id": "tool_select", "title": "Outil de sélection"},
{"id": "tool_source", "title": "Modifier la source"},
{"id": "tool_source_cancel", "textContent": "Annuler"},
{"id": "tool_source_save", "textContent": "Appliquer Modifications"},
{"id": "tool_square", "title": "Carré"},
{"id": "tool_text", "title": "Outil Texte"},
{"id": "tool_topath", "title": "Convertir en chemin"},
{"id": "tool_undo", "title": "Annuler l'action"},
{"id": "tool_ungroup", "title": "Dégrouper les éléments"},
{"id": "tool_wireframe", "title": "Mode Fil de Fer"},
{"id": "tool_zoom", "title": "Zoom"},
{"id": "url_notice", "title": "NOTE: This image cannot be embedded. It will depend on this path to be displayed"},
{"id": "zoom_panel", "title": "Changer le niveau de zoom"},
{"id": "sidepanel_handle", "textContent": "C A L Q U E S", "title": "Tirer vers la gauche/droite pour redimensionner le panneau"},
{
 "js_strings": {
  "QerrorsRevertToSource": "Il y a des erreurs d'analyse syntaxique dans votre code-source SVG.\nRevenir au code-source SVG avant modifications ?",
  "QignoreSourceChanges": "Ignorer les modifications faites à la source SVG ?",
  "QmoveElemsToLayer": "Déplacer les éléments sélectionnés vers le calque '%s' ?",
  "QwantToClear": "Voulez-vous effacer le dessin ?\nL'historique de vos actions sera également effacé !",
  "cancel": "Annuler",
  "defsFailOnSave": "NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.",
  "dupeLayerName": "Il existe déjà un calque de ce nom !",
  "enterNewImgURL": "Entrer la nouvelle URL de l'image",
  "enterNewLayerName": "Veuillez entrer le nouveau nom du calque",
  "enterUniqueLayerName": "Veuillez entrer un nom (unique) pour le calque",
  "exportNoBlur": "Blurred elements will appear as un-blurred",
  "exportNoDashArray": "Strokes will appear filled",
  "exportNoImage": "Image elements will not appear",
  "exportNoText": "Text may not appear as expected",
  "exportNoforeignObject": "foreignObject elements will not appear",
  "featNotSupported": "Fonction non supportée",
  "invalidAttrValGiven": "Valeur fournie invalide",
  "key_backspace": "Suppr.",
  "key_del": "Retour Arr.",
  "key_down": "Bas",
  "key_up": "Haut",
  "layer": "Calque",
  "layerHasThatName": "Le calque porte déjà ce nom",
  "loadingImage": "Loading image, please wait...",
  "noContentToFitTo": "Il n'y a pas de contenu auquel ajuster",
  "noteTheseIssues": "Also note the following issues: ",
  "ok": "OK",
  "pathCtrlPtTooltip": "Glisser-déposer le point de contrôle pour ajuster les propriétés de la courbe",
  "pathNodeTooltip": "Glisser-déposer le nœud pour le déplacer. Double-cliquer le nœud pour changer de type de segment",
  "saveFromBrowser": "Select \"Save As...\" in your browser to save this image as a %s file."
 }
}
]<commit_msg>Update French translation file.<commit_after>[
{"id": "align_relative_to", "title": "Aligner par rapport à ..."},
{"id": "bkgnd_color", "title": "Changer la couleur d'arrière-plan / l'opacité"},
{"id": "circle_cx", "title": "Changer la position horizontale cx du cercle"},
{"id": "circle_cy", "title": "Changer la position verticale cy du cercle"},
{"id": "circle_r", "title": "Changer le rayon du cercle"},
{"id": "connector_no_arrow", "textContent": "Sans flèches"},
{"id": "copyrightLabel", "textContent": "Powered by"},
{"id": "cornerRadiusLabel", "title": "Changer le rayon des coins du rectangle"},
{"id": "curve_segments", "textContent": "Courbe"},
{"id": "ellipse_cx", "title": "Changer la position horizontale cx de l'ellipse"},
{"id": "ellipse_cy", "title": "Changer la position verticale cy de l'ellipse"},
{"id": "ellipse_rx", "title": "Changer le rayon horizontal x de l'ellipse"},
{"id": "ellipse_ry", "title": "Changer le rayon vertical y de l'ellipse"},
{"id": "fill_color", "title": "Changer la couleur de remplissage"},
{"id": "fitToContent", "textContent": "Ajuster au contenu"},
{"id": "fit_to_all", "textContent": "Ajuster au contenu de tous les calques"},
{"id": "fit_to_canvas", "textContent": "Ajuster au canevas"},
{"id": "fit_to_layer_content", "textContent": "Ajuster au contenu du calque"},
{"id": "fit_to_sel", "textContent": "Ajuster à la sélection"},
{"id": "font_family", "title": "Changer la famille de police"},
{"id": "icon_large", "textContent": "Grande"},
{"id": "icon_medium", "textContent": "Moyenne"},
{"id": "icon_small", "textContent": "Petite"},
{"id": "icon_xlarge", "textContent": "Super-Grande"},
{"id": "idLabel", "title": "Identifier l'élément"},
{"id": "image_height", "title": "Changer la hauteur de l'image"},
{"id": "image_opt_embed", "textContent": "Incorporer les images en tant que données (fichiers locaux)"},
{"id": "image_opt_ref", "textContent": "Utiliser la référence des images "},
{"id": "image_url", "title": "Modifier l'URL"},
{"id": "image_width", "title": "Changer la largeur de l'image"},
{"id": "includedImages", "textContent": "Images incorporées"},
{"id": "largest_object", "textContent": "Plus gros objet"},
{"id": "layer_delete", "title": "Supprimer le calque"},
{"id": "layer_down", "title": "Descendre le calque"},
{"id": "layer_new", "title": "Nouveau calque"},
{"id": "layer_rename", "title": "Renommer le calque"},
{"id": "layer_up", "title": "Monter le calque"},
{"id": "layersLabel", "textContent": "Calques :"},
{"id": "line_x1", "title": "Changer la position horizontale x de début de la ligne"},
{"id": "line_x2", "title": "Changer la position horizontale x de fin de la ligne"},
{"id": "line_y1", "title": "Changer la position verticale y de début de la ligne"},
{"id": "line_y2", "title": "Changer la position verticale y de fin de la ligne"},
{"id": "linecap_butt", "title": "Terminaison : Sur le nœud"},
{"id": "linecap_round", "title": "Terminaison : Arrondie"},
{"id": "linecap_square", "title": "Terminaison : Carrée"},
{"id": "linejoin_bevel", "title": "Raccord : Biseauté"},
{"id": "linejoin_miter", "title": "Raccord : Droit"},
{"id": "linejoin_round", "title": "Raccord : Arrondi"},
{"id": "main_icon", "title": "Menu principal"},
{"id": "mode_connect", "title": "Connecter deux objets"},
{"id": "page", "textContent": "Page"},
{"id": "palette", "title": "Cliquer pour changer la couleur de remplissage, Shift-Clic pour changer la couleur de contour"},
{"id": "path_node_x", "title": "Changer la positon horizontale x du nœud"},
{"id": "path_node_y", "title": "Changer la position verticale y du nœud"},
{"id": "rect_height_tool", "title": "Changer la hauteur du rectangle"},
{"id": "rect_width_tool", "title": "Changer la largeur du rectangle"},
{"id": "relativeToLabel", "textContent": "Relativement à:"},
{"id": "seg_type", "title": "Changer le type du Segment"},
{"id": "selLayerLabel", "textContent": "Déplacer éléments vers:"},
{"id": "selLayerNames", "title": "Déplacer les éléments sélectionnés vers un autre calque"},
{"id": "selectedPredefined", "textContent": "Sélectionner prédéfinis:"},
{"id": "selected_objects", "textContent": "Objets sélectionnés"},
{"id": "selected_x", "title": "Changer la position horizontale X"},
{"id": "selected_y", "title": "Changer la position verticale Y"},
{"id": "smallest_object", "textContent": "Plus petit objet"},
{"id": "straight_segments", "textContent": "Droit"},
{"id": "stroke_color", "title": "Changer la couleur du contour"},
{"id": "stroke_style", "title": "Changer le style du contour"},
{"id": "stroke_width", "title": "Changer la largeur du contour de 1, Shift-Click pour changer la largeur de 0.1"},
{"id": "svginfo_bg_note", "textContent": "Note: La toile de fond n'est pas sauvegardée avec l'image."},
{"id": "svginfo_change_background", "textContent": "Toile de fond de l'Éditeur"},
{"id": "svginfo_dim", "textContent": "Dimensions du canevas"},
{"id": "svginfo_editor_prefs", "textContent": "Préférences de l'Éditeur"},
{"id": "svginfo_height", "textContent": "Hauteur:"},
{"id": "svginfo_icons", "textContent": "Taille des icônes"},
{"id": "svginfo_image_props", "textContent": "Propriétés de l'Image"},
{"id": "svginfo_lang", "textContent": "Langue"},
{"id": "svginfo_title", "textContent": "Titre"},
{"id": "svginfo_width", "textContent": "Largeur:"},
{"id": "text", "title": "Changer le contenu du texte"},
{"id": "toggle_stroke_tools", "title": "Montrer/Cacher plus d'outils de Contour"},
{"id": "tool_add_subpath", "title": "Ajouter un sous-chemin"},
{"id": "tool_alignbottom", "title": "Aligner le bas des objets"},
{"id": "tool_aligncenter", "title": "Centrer verticalement"},
{"id": "tool_alignleft", "title": "Aligner les côtés gauches"},
{"id": "tool_alignmiddle", "title": "Centrer horizontalement"},
{"id": "tool_alignright", "title": "Aligner les côtés droits"},
{"id": "tool_aligntop", "title": "Aligner le haut des objets"},
{"id": "tool_angle", "title": "Changer l'angle de rotation"},
{"id": "tool_blur", "title": "Changer la valeur du flou gaussien"},
{"id": "tool_bold", "title": "Texte en gras"},
{"id": "tool_circle", "title": "Cercle"},
{"id": "tool_clear", "textContent": "Nouvelle image"},
{"id": "tool_clone", "title": "Cloner l'élément"},
{"id": "tool_clone_multi", "title": "Cloner les éléments"},
{"id": "tool_delete", "title": "Supprimer l'élément"},
{"id": "tool_delete_multi", "title": "Supprimer les éléments sélectionnés"},
{"id": "tool_docprops", "textContent": "Propriétés du document"},
{"id": "tool_docprops_cancel", "textContent": "Annuler"},
{"id": "tool_docprops_save", "textContent": "OK"},
{"id": "tool_ellipse", "title": "Ellipse"},
{"id": "tool_export", "textContent": "Exporter au format PNG"},
{"id": "tool_eyedropper", "title": "Outil Pipette"},
{"id": "tool_fhellipse", "title": "Ellipse main levée"},
{"id": "tool_fhpath", "title": "Crayon à main levée"},
{"id": "tool_fhrect", "title": "Rectangle main levée"},
{"id": "tool_font_size", "title": "Changer la taille de la police"},
{"id": "tool_group", "title": "Grouper les éléments"},
{"id": "tool_image", "title": "Outil Image"},
{"id": "tool_import", "textContent": "Importer un objet SVG"},
{"id": "tool_italic", "title": "Texte en italique"},
{"id": "tool_line", "title": "Tracer des lignes"},
{"id": "tool_move_bottom", "title": "Déplacer vers le bas"},
{"id": "tool_move_top", "title": "Déplacer vers le haut"},
{"id": "tool_node_clone", "title": "Cloner le nœud"},
{"id": "tool_node_delete", "title": "Supprimer le nœud"},
{"id": "tool_node_link", "title": "Rendre les points de contrôle solidaires"},
{"id": "tool_opacity", "title": "Changer l'opacité de l'élément sélectionné"},
{"id": "tool_open", "textContent": "Ouvrir une image"},
{"id": "tool_openclose_path", "title": "Ouvrir/Fermer sous-chemin"},
{"id": "tool_path", "title": "Outil Chemin"},
{"id": "tool_position", "title": "Aligner l'élément relativement à la Page"},
{"id": "tool_rect", "title": "Rectangle"},
{"id": "tool_redo", "title": "Refaire l'action"},
{"id": "tool_reorient", "title": "Réorienter le chemin"},
{"id": "tool_save", "textContent": "Enregistrer l'image"},
{"id": "tool_select", "title": "Outil de sélection"},
{"id": "tool_source", "title": "Modifier la source"},
{"id": "tool_source_cancel", "textContent": "Annuler"},
{"id": "tool_source_save", "textContent": "Appliquer Modifications"},
{"id": "tool_square", "title": "Carré"},
{"id": "tool_text", "title": "Outil Texte"},
{"id": "tool_topath", "title": "Convertir en chemin"},
{"id": "tool_undo", "title": "Annuler l'action"},
{"id": "tool_ungroup", "title": "Dégrouper les éléments"},
{"id": "tool_wireframe", "title": "Mode Fil de Fer"},
{"id": "tool_zoom", "title": "Zoom"},
{"id": "url_notice", "title": "NOTE: Cette image ne peut être incorporée en tant que données. Le contenu affiché sera celui de l'image située à cette adresse"},
{"id": "zoom_panel", "title": "Changer le niveau de zoom"},
{"id": "sidepanel_handle", "textContent": "C A L Q U E S", "title": "Tirer vers la gauche/droite pour redimensionner le panneau"},
{
 "js_strings": {
  "QerrorsRevertToSource": "Il y a des erreurs d'analyse syntaxique dans votre code-source SVG.\nRevenir au code-source SVG avant modifications ?",
  "QignoreSourceChanges": "Ignorer les modifications faites à la source SVG ?",
  "QmoveElemsToLayer": "Déplacer les éléments sélectionnés vers le calque '%s' ?",
  "QwantToClear": "Voulez-vous effacer le dessin ?\nL'historique de vos actions sera également effacé !",
  "cancel": "Annuler",
  "defsFailOnSave": "NOTE : À cause d'un bug de votre navigateur, cette image peut être affichée de façon incorrecte (dégradés ou éléments manquants). Cependant, une fois enregistrée, elle sera correcte.",
  "dupeLayerName": "Il existe déjà un calque de ce nom !",
  "enterNewImgURL": "Entrer la nouvelle URL de l'image",
  "enterNewLayerName": "Veuillez entrer le nouveau nom du calque",
  "enterUniqueLayerName": "Veuillez entrer un nom (unique) pour le calque",
  "exportNoBlur": "Les éléments ayant du flou gaussien seront affichés sans flou",
  "exportNoDashArray": "Les contours seront affichés remplis",
  "exportNoImage": "Les éléments Image ne seront pas affichés",
  "exportNoText": "Le texte peut être affiché de façon incorrecte",
  "exportNoforeignObject": "Les éléments foreignObject se seront pas affichés",
  "featNotSupported": "Fonction non supportée",
  "invalidAttrValGiven": "Valeur fournie invalide",
  "key_backspace": "Suppr.",
  "key_del": "Retour Arr.",
  "key_down": "Bas",
  "key_up": "Haut",
  "layer": "Calque",
  "layerHasThatName": "Le calque porte déjà ce nom",
  "loadingImage": "Chargement de l'image, veuillez patienter...",
  "noContentToFitTo": "Il n'y a pas de contenu auquel ajuster",
  "noteTheseIssues": "Notez également les problèmes suivants : ",
  "ok": "OK",
  "pathCtrlPtTooltip": "Glisser-déposer le point de contrôle pour ajuster les propriétés de la courbe",
  "pathNodeTooltip": "Glisser-déposer le nœud pour le déplacer. Double-cliquer le nœud pour changer de type de segment",
  "saveFromBrowser": "Selectionner \"Enregistrer sous...\" dans votre navigateur pour sauvegarder l'image en tant que fichier %s."
 }
}
]<|endoftext|>


<commit_before>/*
 * ext-imagelib.js
 *
 * Licensed under the Apache License, Version 2
 *
 * Copyright(c) 2010 Alexis Deveria
 *
 */

svgEditor.addExtension("imagelib", function() {

	var img_libs = [{
			name: 'Demo library (local)',
			url: 'extensions/imagelib/index.html',
			description: 'Demonstration library for SVG-edit on this server'
		},
		{
			name: 'IAN Symbol Libraries',
			url: 'http://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php',
			description: 'Free library of illustrations'
		}
	];

	var xlinkns = "http://www.w3.org/1999/xlink";

	function closeBrowser() {
		$('#imgbrowse_holder').hide();
	}

	function importImage(url) {
		var newImage = svgCanvas.addSvgElementFromJson({
			"element": "image",
			"attr": {
				"x": 0,
				"y": 0,
				"width": 0,
				"height": 0,
				"id": svgCanvas.getNextId(),
				"style": "pointer-events:inherit"
			}
		});
		svgCanvas.clearSelection();
		svgCanvas.addToSelection([newImage]);
		svgCanvas.setImageURL(url);
	}

	var mode = 's';
	var multi_arr = [];
	var cur_meta;
	var tranfer_stopped = false;
	var pending = {};

	 window.addEventListener("message", function(evt) {
		// Receive postMessage data
		var response = evt.data;

		if(!response) {
			$.alert('No data was given', function() {
				if(mode !== 'm') {
					closeBrowser();
				}
			});
			return;
		}

		var char1 = response.charAt(0);

		var svg_str;
		var img_str;

		if(char1 != "{" && tranfer_stopped) {
			tranfer_stopped = false;
			return;
		}

		if(char1 == '|') {
			var secondpos = response.indexOf('|', 1);
			var id = response.substr(1, secondpos-1);
			response = response.substr(secondpos+1);
			char1 = response.charAt(0);

		}

		// Hide possible transfer dialog box
		$('#dialog_box').hide();

		switch (char1) {
			case '{':
				// Metadata
				tranfer_stopped = false;
				var cur_meta = JSON.parse(response);

				pending[cur_meta.id] = cur_meta;

				var message = 'Retrieving "' + (cur_meta.name || 'file') + '"...';

				if(mode != 'm') {
					$.process_cancel(message, function() {
						tranfer_stopped = true;
						// Should a message be sent back to the frame?

						$('#dialog_box').hide();
					});
				} else {
					var entry = $('
' + message + '
').data('id', cur_meta.id);
					preview.append(entry);
					cur_meta.entry = entry;
				}

				return;
			case '<':
				svg_str = true;
				break;
			case 'd':
				if(response.indexOf('data:image/svg+xml') === 0) {
					var pre = 'data:image/svg+xml;base64,';
					var src = response.substring(pre.length);
					response = svgCanvas.Utils.decode64(src);
					svg_str = true;
					break;
				} else if(response.indexOf('data:image/') === 0) {
					img_str = true;
					break;
				}
				// Else fall through
			default:
				// TODO: See if there's a way to base64 encode the binary data stream
// 				var str = 'data:;base64,' + svgCanvas.Utils.encode64(response, true);

				// Assume it's raw image data
// 				importImage(str);

				$.alert('Unexpected data was returned: ' + response, function() {
					if(mode !== 'm') {
						closeBrowser();
					} else {
						pending[id].entry.remove();
					}
				});
				return;
		}

		switch (mode) {
			case 's':
				// Import one
				if(svg_str) {
					svgCanvas.importSvgString(response);
				} else if(img_str) {
					importImage(response);
				}
				closeBrowser();
				break;
			case 'm':
				// Import multiple
				multi_arr.push([(svg_str ? 'svg' : 'img'), response]);
				var cur_meta = pending[id];
				if(svg_str) {
					if(cur_meta && cur_meta.name) {
						title = cur_meta.name;
					}  else {
						// Try to find a title
						var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
						var title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
					}
					if(cur_meta) {
						preview.children().each(function() {
							if($(this).data('id') == id) {
								$(this).text(title);
							}
						});
					} else {
						preview.append('
'+title+'
');
					}
				} else {
					if(cur_meta && cur_meta.preview_url) {
						var title = cur_meta.name || '';
					}
					if(cur_meta && cur_meta.preview_url) {
						var entry = '' + title;
					} else {
						var entry = '';
					}

					if(cur_meta) {
						preview.children().each(function() {
							if($(this).data('id') == id) {
								$(this).html(entry);
							}
						});
					} else {
						preview.append($('
').append(entry));
					}

				}
				break;
			case 'o':
				// Open
				if(!svg_str) break;
				svgEditor.openPrep(function(ok) {
					if(!ok) return;
					svgCanvas.clear();
					svgCanvas.setSvgString(response);
					// updateCanvas();
				});
				closeBrowser();
				break;
		}
	}, true);

	var preview;

	function toggleMulti(show) {
		var submit;

		$('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)});
		if(!preview) {
			preview = $('
').css({
				position: 'absolute',
				top: 45,
				right: 10,
				width: 180,
				bottom: 45,
				background: '#fff',
				overflow: 'auto'
			}).insertAfter('#lib_framewrap');

			submit = $('<button>Import selected</button>').appendTo('#imgbrowse').click(function() {
				$.each(multi_arr, function(i) {
					var type = this[0];
					var data = this[1];
					if(type == 'svg') {
						svgCanvas.importSvgString(data);
					} else {
						importImage(data);
					}
					svgCanvas.moveSelectedElements(i*20, i*20, false);
				});
				preview.empty();
				multi_arr = [];
				$('#imgbrowse_holder').hide();
			}).css({
				position: 'absolute',
				bottom: 10,
				right: -10
			});

		}

		preview.toggle(show);
	}

	function showBrowser() {
		var browser = $('#imgbrowse');
		if(!browser.length) {
			$('

\

').insertAfter('#svg_docprops');
			browser = $('#imgbrowse');

			var all_libs = 'Select an image library';

			var lib_opts = $('
').appendTo(browser);
			var frame = $('').prependTo(browser).hide().wrap('
');

			var header = $('
').prependTo(browser).text(all_libs).css({
				position: 'absolute',
				top: 0,
				left: 0,
				width: '100%'
			});

			var cancel = $('<button>Cancel</button>').appendTo(browser).click(function() {
				$('#imgbrowse_holder').hide();
			}).css({
				position: 'absolute',
				top: 5,
				right: -10
			});

			var leftBlock = $('').css({position:'absolute',top:5,left:10}).appendTo(browser);

			var back = $('<button>Show libraries</button>').appendTo(leftBlock).click(function() {
				frame.attr('src', 'about:blank').hide();
				lib_opts.show();
				header.text(all_libs);
			}).css({
				'margin-right': 5
			});

			var type = $('<select><option value=s>Import single</option><option value=m>Import multiple</option><option value=o>Open for editing</option></select>').appendTo(leftBlock).change(function() {
				mode = $(this).val();
				switch (mode) {
					case 's':
					case 'o':
						toggleMulti(false);
						break;

					case 'm':
						// Import multiple
						toggleMulti(true);
				}
			}).css({
				'margin-top': 10
			});

			cancel.prepend($.getSvgIcon('cancel', true));
			back.prepend($.getSvgIcon('tool_imagelib', true));

			$.each(img_libs, function(i, opts) {
				$('
').appendTo(lib_opts).text(opts.name).click(function() {
					frame.attr('src', opts.url).show();
					header.text(opts.name);
					lib_opts.hide();
				}).append('' + opts.description + '');
			});

		} else {
			$('#imgbrowse_holder').show();
		}
	}

	return {
		svgicons: "extensions/ext-imagelib.xml",
		buttons: [{
			id: "tool_imagelib",
			type: "app_menu", // _flyout
			position: 4,
			title: "Image library",
			events: {
				"mouseup": showBrowser
			}
		}],
		callback: function() {

			$('


<commit_before>import merge from 'lodash/object/merge';
import sample from 'lodash/collection/sample';
import OrbitControls from './OrbitControls';
import TWEEN from 'tween.js';

export default class ModelControls {

  constructor(container, camera, group, config = {}) {

    this.container = container;
    this.camera = camera;
    this.group = group;

    this._animations = [];

    this._startUpAnimations = [
      {
        easing: TWEEN.Easing.Quintic.Out,
        to: {x: (5 * 360 + 45)},
        time: 3500
      },
      {
        easing: TWEEN.Easing.Exponential.InOut,
        to: {x: (3 * 360 + 45)},
        time: 2500
      },
      {
        easing: TWEEN.Easing.Elastic.Out,
        to: {x: (3 * 360 + 45)},
        time: 5500
      },
      {
        easing: TWEEN.Easing.Circular.In,
        to: {x: (4 * 360 + 45)},
        time: 2500
      },
      {
        easing: TWEEN.Easing.Quintic.InOut,
        to: {x: (3 * 360 + 45)},
        time: 2500
      },
      {
        easing: TWEEN.Easing.Exponential.Out,
        to: {x: (4 * 360 + 45)},
        time: 2800
      }
    ];

    // Default configuration params
    this.controlsConfigDefault = {

      startupAnimation: true,

      targetRotationX: 0,
      targetRotationOnMouseDownX: 0,

      targetRotationY: 0,
      targetRotationOnMouseDownY: 0,

      mouseX: 0,
      mouseXOnMouseDown: 0,

      mouseY: 0,
      mouseYOnMouseDown: 0,

      clientHalfX: (this.container.clientWidth / 2),
      clientHalfY: (this.container.clientHeight / 2),

      finalRotationY: null,

      zoom: false
    };

    this.controlsConfig = merge({}, this.controlsConfigDefault, config);

    this._init();

    if (this.controlsConfig.startupAnimation === true) {
      this._createStartUpAnimation();
    }
  }

  update(time) {

    const group = this.group;

    if (this.controls) {
      this.controls.update();
    }

    // Do tweening
    TWEEN.update(time);

    if (group) {

      const cfg = this.controlsConfig;

      group.rotation.y += ( cfg.targetRotationX - group.rotation.y ) * 0.1;

      // vertical rotation
      cfg.finalRotationY = (cfg.targetRotationY - group.rotation.x);
      group.rotation.x += cfg.finalRotationY * 0.05;
    }
  }

  zoomIn(scale = 2) {
    const cam = this.camera;
    const dollyScale = Math.pow(0.95, scale);
    const minZoom = this.controls.minZoom;
    const maxZoom = this.controls.maxZoom;

    cam.zoom = Math.max( minZoom, Math.min( maxZoom, cam.zoom / dollyScale ) );
    cam.updateProjectionMatrix();
  }

  zoomOut(scale = 2) {
    const cam = this.camera;
    const dollyScale = Math.pow(0.95, scale);
    const minZoom = this.controls.minZoom;
    const maxZoom = this.controls.maxZoom;

    cam.zoom = Math.max( minZoom, Math.min( maxZoom, cam.zoom * dollyScale ) );
    cam.updateProjectionMatrix();
  }

  destroy() {
    this._removeEventListener();

    // Remove orbit control
    if (this.controls) {
      this.controls.dispose();
    }

    this._clearAnimations();
    this._animations = [];
  }

  _clearAnimations() {

    if (this._animations && this._animations.length > 0) {

      while (this._animations.length > 0) {
        TWEEN.remove(this._animations.pop());
      }
    }
  }

  _createStartUpAnimation() {

    const {targetRotationY, targetRotationX} = this.controlsConfig;
    const self = this;

    const coords = {
      x: targetRotationX / Math.PI * 180,
      y: targetRotationY / Math.PI * 180
    };

    this._clearAnimations();

    const anim = sample(this._startUpAnimations);

    let tween1 = new TWEEN.Tween(coords)
      .easing(anim.easing)
      .to(anim.to, anim.time)
      .onUpdate(function() {
        self.controlsConfig.targetRotationX = this.x * Math.PI / 180;
      })
      .start();

    this._animations.push(tween1);

    let tween2 = new TWEEN.Tween(coords)
      .easing(TWEEN.Easing.Exponential.Out)
      .to({ y: 45 }, 1500)
      .onUpdate(function() {
        self.controlsConfig.targetRotationY = this.y * Math.PI / 180;
      })
      .start();

    this._animations.push(tween2);
  }

  set zoom(val) {
    this.controls.enableZoom = val;
    this.controlsConfig.zoom = val;
  }

  get zoom() {
    return this.controlsConfig;
  }

  _init() {

    // Clean registered event listener
    this._removeEventListener();
    // this.controlsConfig = merge({}, this.controlsConfigDefault);
    this._setupListener();

    // Delecate to orbit controls
    const controls = new OrbitControls(this.camera, this.container);

    controls.enableKeys = false;
    controls.enableRotate = false;
    controls.enablePan = false;
    controls.enableDamping = false;
    controls.enableZoom = this.controlsConfig.zoom;

    let bb = new THREE.Box3();
    bb.setFromObject(this.group);
    bb.center(controls.target);

    this.controls = controls;
  }

  _setupListener() {

    const container = this.container;

    // Add resize listener
    this._resizeListener = (evt)=>{ this._onWindowResize(evt); };
    window.addEventListener('resize', this._resizeListener, false);

    // Controls
    this._mouseDownListener = (e) => { this._onMouseDown(e); };
    this._mouseMoveListener = (e) => { this._onMouseMove(e); };
    this._mouseUpListener = (e) => { this._onMouseUp(e); };
    this._mouseOutListener = (e) => { this._onMouseOut(e); };
    this._touchStartListener = (e) => { this._onTouchStart(e); };
    this._touchEndListener = (e) => { this._onTouchEnd(e); };
    this._touchMoveListener = (e) => { this._onTouchMove(e); };

    // Mouse / Touch events
    container.addEventListener( 'mousedown', this._mouseDownListener, false );
    container.addEventListener( 'touchstart', this._touchStartListener, false );
    container.addEventListener( 'touchmove', this._touchMoveListener, false );
  }

  _removeEventListener() {

    const container = this.container;

    // Remove resize listener
    window.removeEventListener('resize', this._resizeListener, false);
    this._resizeListener = null;

    // Remove model spinning controls
    container.removeEventListener( 'mouseup',    this._mouseUpListener, false );
    container.removeEventListener( 'mousemove',  this._mouseMoveListener, false );
    container.removeEventListener( 'mousedown',  this._mouseDownListener, false );
    container.removeEventListener( 'touchstart', this._touchStartListener, false );
    container.removeEventListener( 'touchmove',  this._touchMoveListener, false );
  }

  _onWindowResize() {

    ['controlsConfig', 'controlsConfigDefault'].forEach((key)=>{

      if (this.hasOwnProperty(key)) {
        this[key].clientHalfX = (this.container.clientWidth / 2);
        this[key].clientHalfY = (this.container.clientHeight / 2);
      }
    });
  }

  _onMouseDown(evt) {

    evt.preventDefault();

    const container = this.container;
    const cfg = this.controlsConfig;

    if (container) {

      const { clientX, clientY } = evt;

      this._clearAnimations();

      container.addEventListener('mousemove', this._mouseMoveListener, false);
      container.addEventListener('mouseup', this._mouseUpListener, false);
      container.addEventListener('mouseout', this._mouseOutListener, false);

      cfg.mouseXOnMouseDown = clientX - cfg.clientHalfX;
      cfg.targetRotationOnMouseDownX = cfg.targetRotationX;

      cfg.mouseYOnMouseDown = clientY - cfg.clientHalfY;
      cfg.targetRotationOnMouseDownY = cfg.targetRotationY;
    }

  }

  _onMouseMove(evt) {

    if (evt) {

      const cfg = this.controlsConfig;

      cfg.mouseX = evt.clientX - cfg.clientHalfX;
      cfg.mouseY = evt.clientY - cfg.clientHalfY;

      cfg.targetRotationY = cfg.targetRotationOnMouseDownY + (cfg.mouseY - cfg.mouseYOnMouseDown) * 0.02;
      cfg.targetRotationX = cfg.targetRotationOnMouseDownX + (cfg.mouseX - cfg.mouseXOnMouseDown) * 0.02;
    }
  }

  _onMouseUp() {

    const {container} = this;

    if (container) {
      container.removeEventListener( 'mousemove', this._mouseMoveListener, false );
      container.removeEventListener( 'mouseup', this._mouseUpListener, false );
      container.removeEventListener( 'mouseout', this._mouseOutListener, false );
    }
  }

  _onMouseOut() {

    const {container} = this;

    if (container) {
      container.removeEventListener('mousemove', this._mouseMoveListener, false);
      container.removeEventListener('mouseup', this._mouseUpListener, false);
      container.removeEventListener('mouseout', this._mouseOutListener, false);
    }
  }

  _onTouchStart(evt = {touches: [] }) {

    const touches = evt.touches;
    const cfg = this.controlsConfig;

    if (touches.length === 1) {

      evt.preventDefault();
      const {pageX, pageY} = touches[0];

      cfg.mouseXOnMouseDown = pageX - cfg.clientHalfX;
      cfg.targetRotationOnMouseDownX = cfg.targetRotationX;

      cfg.mouseYOnMouseDown = pageY - cfg.clientHalfY;
      cfg.targetRotationOnMouseDownY = cfg.targetRotationY;
    }
  }

  _onTouchEnd(evt = {touches: [] }) {

    const touches = evt.touches;
    const cfg = this.controlsConfig;

    if (touches.length === 1) {

      evt.preventDefault();

      const {pageX, pageY} = touches[0];

      cfg.mouseX = pageX - cfg.clientHalfX;
      cfg.targetRotationX = cfg.targetRotationOnMouseDownX + ( cfg.mouseX - cfg.mouseXOnMouseDown ) * 0.05;

      cfg.mouseY = pageY - cfg.clientHalfY;
      cfg.targetRotationY = cfg.targetRotationOnMouseDownY + (cfg.mouseY - cfg.mouseYOnMouseDown) * 0.05;

    }
  }

  _onTouchMove(evt = {touches: [] }) {

    const touches = evt.touches;
    const cfg = this.controlsConfig;

    if (touches.length === 1 ) {

      evt.preventDefault();
      const {pageX, pageY} = touches[0];

      cfg.mouseX = pageX - cfg.clientHalfX;
      cfg.targetRotationX = cfg.targetRotationOnMouseDownX + ( cfg.mouseX - cfg.mouseXOnMouseDown ) * 0.05;

      cfg.mouseY = pageY - cfg.clientHalfY;
      cfg.targetRotationY = cfg.targetRotationOnMouseDownY + (cfg.mouseY - cfg.mouseYOnMouseDown) * 0.05;
    }
  }
}
<commit_msg>add zoom tweening<commit_after>import merge from 'lodash/object/merge';
import sample from 'lodash/collection/sample';
import OrbitControls from './OrbitControls';
import TWEEN from 'tween.js';

export default class ModelControls {

  constructor(container, camera, group, config = {}) {

    this.container = container;
    this.camera = camera;
    this.group = group;

    this._animations = [];
    this._zoomTween = null;

    this._startUpAnimations = [
      {
        easing: TWEEN.Easing.Quintic.Out,
        to: {x: (5 * 360 + 45)},
        time: 3500
      },
      {
        easing: TWEEN.Easing.Exponential.InOut,
        to: {x: (3 * 360 + 45)},
        time: 2500
      },
      {
        easing: TWEEN.Easing.Elastic.Out,
        to: {x: (3 * 360 + 45)},
        time: 5500
      },
      {
        easing: TWEEN.Easing.Circular.In,
        to: {x: (4 * 360 + 45)},
        time: 2500
      },
      {
        easing: TWEEN.Easing.Quintic.InOut,
        to: {x: (3 * 360 + 45)},
        time: 2500
      },
      {
        easing: TWEEN.Easing.Exponential.Out,
        to: {x: (4 * 360 + 45)},
        time: 2800
      }
    ];

    // Default configuration params
    this.controlsConfigDefault = {

      startupAnimation: true,

      targetRotationX: 0,
      targetRotationOnMouseDownX: 0,

      targetRotationY: 0,
      targetRotationOnMouseDownY: 0,

      mouseX: 0,
      mouseXOnMouseDown: 0,

      mouseY: 0,
      mouseYOnMouseDown: 0,

      clientHalfX: (this.container.clientWidth / 2),
      clientHalfY: (this.container.clientHeight / 2),

      finalRotationY: null,

      zoom: false
    };

    this.controlsConfig = merge({}, this.controlsConfigDefault, config);

    this._init();

    if (this.controlsConfig.startupAnimation === true) {
      this._createStartUpAnimation();
    }
  }

  update(time) {

    const group = this.group;

    if (this.controls) {
      this.controls.update();
    }

    // Do tweening
    TWEEN.update(time);

    if (group) {

      const cfg = this.controlsConfig;

      group.rotation.y += ( cfg.targetRotationX - group.rotation.y ) * 0.1;

      // vertical rotation
      cfg.finalRotationY = (cfg.targetRotationY - group.rotation.x);
      group.rotation.x += cfg.finalRotationY * 0.05;
    }
  }

  zoomIn(scale = 2) {

    TWEEN.remove(this._zoomTween);

    const cam = this.camera;
    const dollyScale = Math.pow(0.95, scale);
    const minZoom = this.controls.minZoom;
    const maxZoom = this.controls.maxZoom;
    const zoomLvl = Math.max( minZoom, Math.min( maxZoom, cam.zoom / dollyScale ) );

    this._dollyZoom(zoomLvl);
  }

  zoomOut(scale = 2) {

    TWEEN.remove(this._zoomTween);

    const cam = this.camera;
    const dollyScale = Math.pow(0.95, scale);
    const minZoom = this.controls.minZoom;
    const maxZoom = this.controls.maxZoom;
    const zoomLvl = Math.max( minZoom, Math.min( maxZoom, cam.zoom * dollyScale ) );

    this._dollyZoom(zoomLvl);
  }

  _dollyZoom(zoomLvl) {

    const cam = this.camera;
    const tween = new TWEEN.Tween({zoom: cam.zoom });
    tween.to({ zoom: zoomLvl }, 300);
    tween.onUpdate(function() {
      cam.zoom = this.zoom;
      cam.updateProjectionMatrix();
    });
    tween.start();

    this._zoomTween = tween;
    return tween;
  }

  destroy() {
    this._removeEventListener();

    // Remove orbit control
    if (this.controls) {
      this.controls.dispose();
    }

    this._clearAnimations();
    this._animations = [];
  }

  _clearAnimations() {

    if (this._animations && this._animations.length > 0) {

      while (this._animations.length > 0) {
        TWEEN.remove(this._animations.pop());
      }
    }

    TWEEN.remove(this._zoomTween);
  }

  _createStartUpAnimation() {

    const {targetRotationY, targetRotationX} = this.controlsConfig;
    const self = this;

    const coords = {
      x: targetRotationX / Math.PI * 180,
      y: targetRotationY / Math.PI * 180
    };

    this._clearAnimations();

    const anim = sample(this._startUpAnimations);

    let tween1 = new TWEEN.Tween(coords)
      .easing(anim.easing)
      .to(anim.to, anim.time)
      .onUpdate(function() {
        self.controlsConfig.targetRotationX = this.x * Math.PI / 180;
      })
      .start();

    this._animations.push(tween1);

    let tween2 = new TWEEN.Tween(coords)
      .easing(TWEEN.Easing.Exponential.Out)
      .to({ y: 45 }, 1500)
      .onUpdate(function() {
        self.controlsConfig.targetRotationY = this.y * Math.PI / 180;
      })
      .start();

    this._animations.push(tween2);
  }

  set zoom(val) {
    this.controls.enableZoom = val;
    this.controlsConfig.zoom = val;
  }

  get zoom() {
    return this.controlsConfig;
  }

  _init() {

    // Clean registered event listener
    this._removeEventListener();
    // this.controlsConfig = merge({}, this.controlsConfigDefault);
    this._setupListener();

    // Delecate to orbit controls
    const controls = new OrbitControls(this.camera, this.container);

    controls.enableKeys = false;
    controls.enableRotate = false;
    controls.enablePan = false;
    controls.enableDamping = false;
    controls.enableZoom = this.controlsConfig.zoom;

    let bb = new THREE.Box3();
    bb.setFromObject(this.group);
    bb.center(controls.target);

    this.controls = controls;
  }

  _setupListener() {

    const container = this.container;

    // Add resize listener
    this._resizeListener = (evt)=>{ this._onWindowResize(evt); };
    window.addEventListener('resize', this._resizeListener, false);

    // Controls
    this._mouseDownListener = (e) => { this._onMouseDown(e); };
    this._mouseMoveListener = (e) => { this._onMouseMove(e); };
    this._mouseUpListener = (e) => { this._onMouseUp(e); };
    this._mouseOutListener = (e) => { this._onMouseOut(e); };
    this._touchStartListener = (e) => { this._onTouchStart(e); };
    this._touchEndListener = (e) => { this._onTouchEnd(e); };
    this._touchMoveListener = (e) => { this._onTouchMove(e); };

    // Mouse / Touch events
    container.addEventListener( 'mousedown', this._mouseDownListener, false );
    container.addEventListener( 'touchstart', this._touchStartListener, false );
    container.addEventListener( 'touchmove', this._touchMoveListener, false );
  }

  _removeEventListener() {

    const container = this.container;

    // Remove resize listener
    window.removeEventListener('resize', this._resizeListener, false);
    this._resizeListener = null;

    // Remove model spinning controls
    container.removeEventListener( 'mouseup',    this._mouseUpListener, false );
    container.removeEventListener( 'mousemove',  this._mouseMoveListener, false );
    container.removeEventListener( 'mousedown',  this._mouseDownListener, false );
    container.removeEventListener( 'touchstart', this._touchStartListener, false );
    container.removeEventListener( 'touchmove',  this._touchMoveListener, false );
  }

  _onWindowResize() {

    ['controlsConfig', 'controlsConfigDefault'].forEach((key)=>{

      if (this.hasOwnProperty(key)) {
        this[key].clientHalfX = (this.container.clientWidth / 2);
        this[key].clientHalfY = (this.container.clientHeight / 2);
      }
    });
  }

  _onMouseDown(evt) {

    evt.preventDefault();

    const container = this.container;
    const cfg = this.controlsConfig;

    if (container) {

      const { clientX, clientY } = evt;

      this._clearAnimations();

      container.addEventListener('mousemove', this._mouseMoveListener, false);
      container.addEventListener('mouseup', this._mouseUpListener, false);
      container.addEventListener('mouseout', this._mouseOutListener, false);

      cfg.mouseXOnMouseDown = clientX - cfg.clientHalfX;
      cfg.targetRotationOnMouseDownX = cfg.targetRotationX;

      cfg.mouseYOnMouseDown = clientY - cfg.clientHalfY;
      cfg.targetRotationOnMouseDownY = cfg.targetRotationY;
    }

  }

  _onMouseMove(evt) {

    if (evt) {

      const cfg = this.controlsConfig;

      cfg.mouseX = evt.clientX - cfg.clientHalfX;
      cfg.mouseY = evt.clientY - cfg.clientHalfY;

      cfg.targetRotationY = cfg.targetRotationOnMouseDownY + (cfg.mouseY - cfg.mouseYOnMouseDown) * 0.02;
      cfg.targetRotationX = cfg.targetRotationOnMouseDownX + (cfg.mouseX - cfg.mouseXOnMouseDown) * 0.02;
    }
  }

  _onMouseUp() {

    const {container} = this;

    if (container) {
      container.removeEventListener( 'mousemove', this._mouseMoveListener, false );
      container.removeEventListener( 'mouseup', this._mouseUpListener, false );
      container.removeEventListener( 'mouseout', this._mouseOutListener, false );
    }
  }

  _onMouseOut() {

    const {container} = this;

    if (container) {
      container.removeEventListener('mousemove', this._mouseMoveListener, false);
      container.removeEventListener('mouseup', this._mouseUpListener, false);
      container.removeEventListener('mouseout', this._mouseOutListener, false);
    }
  }

  _onTouchStart(evt = {touches: [] }) {

    const touches = evt.touches;
    const cfg = this.controlsConfig;

    if (touches.length === 1) {

      evt.preventDefault();
      const {pageX, pageY} = touches[0];

      cfg.mouseXOnMouseDown = pageX - cfg.clientHalfX;
      cfg.targetRotationOnMouseDownX = cfg.targetRotationX;

      cfg.mouseYOnMouseDown = pageY - cfg.clientHalfY;
      cfg.targetRotationOnMouseDownY = cfg.targetRotationY;
    }
  }

  _onTouchEnd(evt = {touches: [] }) {

    const touches = evt.touches;
    const cfg = this.controlsConfig;

    if (touches.length === 1) {

      evt.preventDefault();

      const {pageX, pageY} = touches[0];

      cfg.mouseX = pageX - cfg.clientHalfX;
      cfg.targetRotationX = cfg.targetRotationOnMouseDownX + ( cfg.mouseX - cfg.mouseXOnMouseDown ) * 0.05;

      cfg.mouseY = pageY - cfg.clientHalfY;
      cfg.targetRotationY = cfg.targetRotationOnMouseDownY + (cfg.mouseY - cfg.mouseYOnMouseDown) * 0.05;

    }
  }

  _onTouchMove(evt = {touches: [] }) {

    const touches = evt.touches;
    const cfg = this.controlsConfig;

    if (touches.length === 1 ) {

      evt.preventDefault();
      const {pageX, pageY} = touches[0];

      cfg.mouseX = pageX - cfg.clientHalfX;
      cfg.targetRotationX = cfg.targetRotationOnMouseDownX + ( cfg.mouseX - cfg.mouseXOnMouseDown ) * 0.05;

      cfg.mouseY = pageY - cfg.clientHalfY;
      cfg.targetRotationY = cfg.targetRotationOnMouseDownY + (cfg.mouseY - cfg.mouseYOnMouseDown) * 0.05;
    }
  }
}
<|endoftext|>


<commit_before>/*jshint node:true*/

var EOL         = require('os').EOL;
var chalk       = require('chalk');
var fs          = require('fs-extra');
var Promise     = require('rsvp');
var readFile    = Promise.denodeify(fs.readFile);

module.exports = {
  description: 'ember-data-contentful',

  normalizeEntityName: function() {
  },

  availableOptions: [
    {
      name: 'space',
      type: String
    }, {
      name: 'accesstoken',
      type: String
    }
  ],

  afterInstall: function(options) {
    var self = this;
    var contentfulSpace = options.space || 'YOUR-CONTENTFUL-SPACE';
    var contentfulAccessToken = options.accesstoken || 'YOUR-CONTENTFUL-ACCESS-TOKEN';

    return this.addAddonToProject('ember-network', '0.2.0')
    .then(function() {
      return self.addToConfig('contentfulSpace', '\'' + contentfulSpace + '\'');
    })
    .then(function () {
      return self.addToConfig('contentfulAccessToken', '\'' + contentfulAccessToken + '\'');
    })
    .then(function () {
      var output = EOL;
      output += chalk.yellow('ember-data-contentful') + ' has been installed. Please configure your contentful space and accessToekn in ' + chalk.green('config/environment.js') + EOL;
      console.log(output);
    });
  },

  addToConfig: function (key, value) {
    var self = this;
    return this.fileContains('config/environment.js', key + ':').then(function (contains) {
      if (contains) { return true; }

      var options = { after: '    environment: environment,' + EOL };
      return self.insertIntoFile('config/environment.js', '    ' + key + ': ' + value + ',', options);
    });
  },

  fileContains: function (filePath, snippet) {
    return readFile(filePath).then(function (fileContents) {
      return fileContents.toString().indexOf(snippet) !== -1;
    });
  }
};
<commit_msg>fixed typo in console log<commit_after>/*jshint node:true*/

var EOL         = require('os').EOL;
var chalk       = require('chalk');
var fs          = require('fs-extra');
var Promise     = require('rsvp');
var readFile    = Promise.denodeify(fs.readFile);

module.exports = {
  description: 'ember-data-contentful',

  normalizeEntityName: function() {
  },

  availableOptions: [
    {
      name: 'space',
      type: String
    }, {
      name: 'accesstoken',
      type: String
    }
  ],

  afterInstall: function(options) {
    var self = this;
    var contentfulSpace = options.space || 'YOUR-CONTENTFUL-SPACE';
    var contentfulAccessToken = options.accesstoken || 'YOUR-CONTENTFUL-ACCESS-TOKEN';

    return this.addAddonToProject('ember-network', '0.2.0')
    .then(function() {
      return self.addToConfig('contentfulSpace', '\'' + contentfulSpace + '\'');
    })
    .then(function () {
      return self.addToConfig('contentfulAccessToken', '\'' + contentfulAccessToken + '\'');
    })
    .then(function () {
      var output = EOL;
      output += chalk.yellow('ember-data-contentful') + ' has been installed. Please configure your contentful space and accessToken in ' + chalk.green('config/environment.js') + EOL;
      console.log(output);
    });
  },

  addToConfig: function (key, value) {
    var self = this;
    return this.fileContains('config/environment.js', key + ':').then(function (contains) {
      if (contains) { return true; }

      var options = { after: '    environment: environment,' + EOL };
      return self.insertIntoFile('config/environment.js', '    ' + key + ': ' + value + ',', options);
    });
  },

  fileContains: function (filePath, snippet) {
    return readFile(filePath).then(function (fileContents) {
      return fileContents.toString().indexOf(snippet) !== -1;
    });
  }
};
<|endoftext|>


<commit_before>
const PAYLOAD_FILE = 'payload';
const PAYLOAD_MANIFEST = 'manifest';
const TAG_MANIFEST = 'tagmanifest';
const TAG_FILE = 'tagfile';

module.exports = class BagItFile {

    constructor(absSourcePath, relDestPath, stats) {
        this.absSourcePath = absSourcePath;
        this.relDestPath = relDestPath;
        this.stats = stats;
        this.fileType = BagItFile.getFileType(relDestPath);
        this.checksums = {};
    }

    static getFileType(relDestPath) {
        if (relDestPath.startsWith('data/')) {
            return PAYLOAD_FILE;
        } else if (relDestPath.startsWith('manifest-')) {
            return PAYLOAD_MANIFEST;
        } else if (relDestPath.startsWith('tagmanifest-')) {
            return TAG_MANIFEST;
        }
        return TAG_FILE;
    }
}
<commit_msg>Added BagItFile.getManifestEntry<commit_after>
const PAYLOAD_FILE = 'payload';
const PAYLOAD_MANIFEST = 'manifest';
const TAG_MANIFEST = 'tagmanifest';
const TAG_FILE = 'tagfile';

module.exports = class BagItFile {

    constructor(absSourcePath, relDestPath, stats) {
        this.absSourcePath = absSourcePath;
        this.relDestPath = relDestPath;
        this.stats = stats;
        this.fileType = BagItFile.getFileType(relDestPath);
        // checksums:
        // key = algorithm name ('md5', 'sha256', etc.)
        // value = digest
        this.checksums = {};
    }

    // Returns the manifest entry for the specified algorithm,
    // or throws an exception if the checksum for that algorithm
    // is not present. The format of the returned string is suitable
    // for printing into a payload manifest or tag manifest.
    getManifestEntry(algorithm) {
        var checksum = this.checksums[algorithm];
        if (checksum === undefined || !checksum) {
            throw `No ${algorithm} digest for ${this.absSourcePath}`;
        }
        return `${checksum} ${this.relDestPath}`;
    }

    static getFileType(relDestPath) {
        if (relDestPath.startsWith('data/')) {
            return PAYLOAD_FILE;
        } else if (relDestPath.startsWith('manifest-')) {
            return PAYLOAD_MANIFEST;
        } else if (relDestPath.startsWith('tagmanifest-')) {
            return TAG_MANIFEST;
        }
        return TAG_FILE;
    }
}
<|endoftext|>


<commit_before>/*
 * genphonefmt.js - ilib tool to generate the json phonefmt information from the libphonefmt-js
 * library
 *
 * Copyright © 2019 JEDLSoft
 *
 * 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.
 */

 /*
 * This code is intended to be run under node.js
 */
var fs = require('fs');
var util = require('util');
var path = require('path');
var common = require('../cldr/common.js');
var mkdirs = common.makeDirs;
var toDir = "tmp";

var libphonefmt = require('libphonenumber-js/max');
var sampleNums = require("./exampleNums.json");

var numberTemplate =[];
var wholeTemplate = {};
var filename;
var testNumber, fixedlineNumber, mobileNumber, serviceNumber, i;
var trunkNumber;

for (country in sampleNums) {
    wholeTemplate = {};
    if (country === "001") break;
    console.log("\n-----------------------------------------------");

    filename = path.join(toDir, 'und', country)

    asYouType = new libphonefmt.AsYouType(country);
    numbers = sampleNums[country];

    asYouType = new libphonefmt.AsYouType(country);
    fixedlineNumber = numbers["fixed_line"];
    mobileNumber = numbers ["mobile"];
    serviceNumber = numbers ["toll_free"];

    trunkNumber = (numbers["trunkCode"] ? numbers["trunkCode"] : "");
    console.log(country + "  trunkNumber .... " + trunkNumber);

    if (fixedlineNumber && (libphonefmt.parsePhoneNumber(fixedlineNumber, country).isValid())) {
        fixedlineNumber = trunkNumber + fixedlineNumber;
        asYouType.input(fixedlineNumber);

        if (asYouType.getTemplate() !== undefined) {
            console.log(country, " country has a valid Fixedline Number: " , fixedlineNumber, " ", asYouType.getTemplate());
            if (!fs.existsSync(filename)) {
               console.log("Create a directory....", filename);
               mkdirs(filename);
            }
            asYouType.reset();
            numberTemplate =[];

            for (i=1; i< fixedlineNumber.length; i++) {
                testNumber = fixedlineNumber.substring(0,i);
                inputNum = asYouType.input(testNumber);
                console.log("###", ( typeof asYouType.getTemplate() !== "undefined" ? asYouType.getTemplate(): "x"));
                if (i == 1 && (typeof asYouType.getTemplate() === 'undefined')) {
                    numberTemplate.push("x");
                } else {
                    numberTemplate.push(asYouType.getTemplate());
                }
                asYouType.reset();
            }
            wholeTemplate["fixedline_exampleNumber"] = fixedlineNumber;
            wholeTemplate["fixedline_template"] = numberTemplate;
        }
    }

    if (mobileNumber && (libphonefmt.parsePhoneNumber(mobileNumber, country).isValid())) {
        mobileNumber = trunkNumber + mobileNumber;
        asYouType.input(mobileNumber);

        if (asYouType.getTemplate() !== undefined) {
            console.log(country, " country has a valid Mobile Number: " , mobileNumber, " ", asYouType.getTemplate());
            if (!fs.existsSync(filename)) {
               console.log("Create a directory....", filename);
               mkdirs(filename);
            }

            asYouType.reset();
            numberTemplate =[];

            for (i=1; i< mobileNumber.length; i++) {
                testNumber = mobileNumber.substring(0,i);
                inputNum = asYouType.input(testNumber);
                console.log("###", ( typeof asYouType.getTemplate() !== "undefined" ? asYouType.getTemplate(): "x"));
                if (i == 1 && (typeof asYouType.getTemplate() === 'undefined')) {
                    numberTemplate.push("x");
                } else {
                    numberTemplate.push(asYouType.getTemplate());
                }
                asYouType.reset();
            }
            wholeTemplate["mobile_exampleNumber"] = mobileNumber;
            wholeTemplate["mobile_template"] = numberTemplate;
        }
    }

    if (serviceNumber && (libphonefmt.parsePhoneNumber(serviceNumber, country).isValid())) {
        serviceNumber = trunkNumber + serviceNumber;
        asYouType.input(serviceNumber);

        if (asYouType.getTemplate() !== undefined) {
            console.log(country, " country has a valid Service Number: " , serviceNumber, " ", asYouType.getTemplate());
            if (!fs.existsSync(filename)) {
               console.log("Create a directory....", filename);
               mkdirs(filename);
            }

            asYouType.reset();
            numberTemplate =[];

            for (i=1; i< serviceNumber.length; i++) {
                testNumber = serviceNumber.substring(0,i);
                inputNum = asYouType.input(testNumber);
                console.log("###", ( typeof asYouType.getTemplate() !== "undefined" ? asYouType.getTemplate(): "x"));
                if (i == 1 && (typeof asYouType.getTemplate() === 'undefined')) {
                    numberTemplate.push("x");
                } else {
                    numberTemplate.push(asYouType.getTemplate());
                }
                asYouType.reset();
            }
            wholeTemplate["service_exampleNumber"] = serviceNumber;
            wholeTemplate["service_template"] = numberTemplate;
        }
    }

    for (var key in wholeTemplate) {
        if (wholeTemplate.hasOwnProperty(key)) {
            writefile = path.join(filename, "phonefmt.json");
            console.log("Creating " + filename + "/phonefmt.json")
            fs.writeFileSync(writefile, JSON.stringify(wholeTemplate, true, 4), "utf-8");
            break;
        }
        break;
    }
 }<commit_msg>Remove duplicate code<commit_after>/*
 * genphonefmt.js - ilib tool to generate the json phonefmt information from the libphonefmt-js
 * library
 *
 * Copyright © 2019 JEDLSoft
 *
 * 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.
 */

 /*
 * This code is intended to be run under node.js
 */
var fs = require('fs');
var util = require('util');
var path = require('path');
var common = require('../cldr/common.js');
var mkdirs = common.makeDirs;
var toDir = "tmp";

var libphonefmt = require('libphonenumber-js/max');
var sampleNums = require("./exampleNums.json");

var numberTemplate =[];
var wholeTemplate = {};
var filename;
var testNumber, fixedlineNumber, mobileNumber, serviceNumber, i;
var trunkNumber;

for (country in sampleNums) {
    wholeTemplate = {};

    if (country === "001") break;
    console.log("\n-----------------------------------------------");

    filename = path.join(toDir, 'und', country)

    asYouType = new libphonefmt.AsYouType(country);
    numbers = sampleNums[country];

    fixedlineNumber = numbers["fixed_line"];
    mobileNumber = numbers ["mobile"];
    serviceNumber = numbers ["toll_free"];

    trunkNumber = (numbers["trunkCode"] ? numbers["trunkCode"] : "");
    console.log(country + "  trunkNumber .... " + trunkNumber);

    if (fixedlineNumber && (libphonefmt.parsePhoneNumber(fixedlineNumber, country).isValid())) {
        fixedlineNumber = trunkNumber + fixedlineNumber;
        asYouType.input(fixedlineNumber);

        if (asYouType.getTemplate() !== undefined) {
            console.log(country, " country has a valid Fixedline Number: " , fixedlineNumber, " ", asYouType.getTemplate());
            if (!fs.existsSync(filename)) {
               console.log("Create a directory....", filename);
               mkdirs(filename);
            }
            asYouType.reset();
            numberTemplate =[];

            for (i=1; i< fixedlineNumber.length; i++) {
                testNumber = fixedlineNumber.substring(0,i);
                inputNum = asYouType.input(testNumber);
                console.log("###", ( typeof asYouType.getTemplate() !== "undefined" ? asYouType.getTemplate(): "x"));
                if (i == 1 && (typeof asYouType.getTemplate() === 'undefined')) {
                    numberTemplate.push("x");
                } else {
                    numberTemplate.push(asYouType.getTemplate());
                }
                asYouType.reset();
            }
            wholeTemplate["fixedline_exampleNumber"] = fixedlineNumber;
            wholeTemplate["fixedline_template"] = numberTemplate;
        }
    }

    if (mobileNumber && (libphonefmt.parsePhoneNumber(mobileNumber, country).isValid())) {
        mobileNumber = trunkNumber + mobileNumber;
        asYouType.input(mobileNumber);

        if (asYouType.getTemplate() !== undefined) {
            console.log(country, " country has a valid Mobile Number: " , mobileNumber, " ", asYouType.getTemplate());
            if (!fs.existsSync(filename)) {
               console.log("Create a directory....", filename);
               mkdirs(filename);
            }

            asYouType.reset();
            numberTemplate =[];

            for (i=1; i< mobileNumber.length; i++) {
                testNumber = mobileNumber.substring(0,i);
                inputNum = asYouType.input(testNumber);
                console.log("###", ( typeof asYouType.getTemplate() !== "undefined" ? asYouType.getTemplate(): "x"));
                if (i == 1 && (typeof asYouType.getTemplate() === 'undefined')) {
                    numberTemplate.push("x");
                } else {
                    numberTemplate.push(asYouType.getTemplate());
                }
                asYouType.reset();
            }
            wholeTemplate["mobile_exampleNumber"] = mobileNumber;
            wholeTemplate["mobile_template"] = numberTemplate;
        }
    }

    if (serviceNumber && (libphonefmt.parsePhoneNumber(serviceNumber, country).isValid())) {
        serviceNumber = trunkNumber + serviceNumber;
        asYouType.input(serviceNumber);

        if (asYouType.getTemplate() !== undefined) {
            console.log(country, " country has a valid Service Number: " , serviceNumber, " ", asYouType.getTemplate());
            if (!fs.existsSync(filename)) {
               console.log("Create a directory....", filename);
               mkdirs(filename);
            }

            asYouType.reset();
            numberTemplate =[];

            for (i=1; i< serviceNumber.length; i++) {
                testNumber = serviceNumber.substring(0,i);
                inputNum = asYouType.input(testNumber);
                console.log("###", ( typeof asYouType.getTemplate() !== "undefined" ? asYouType.getTemplate(): "x"));
                if (i == 1 && (typeof asYouType.getTemplate() === 'undefined')) {
                    numberTemplate.push("x");
                } else {
                    numberTemplate.push(asYouType.getTemplate());
                }
                asYouType.reset();
            }
            wholeTemplate["service_exampleNumber"] = serviceNumber;
            wholeTemplate["service_template"] = numberTemplate;
        }
    }

    for (var key in wholeTemplate) {
        if (wholeTemplate.hasOwnProperty(key)) {
            writefile = path.join(filename, "phonefmt.json");
            console.log("Creating " + filename + "/phonefmt.json")
            fs.writeFileSync(writefile, JSON.stringify(wholeTemplate, true, 4), "utf-8");
            break;
        }
        break;
    }
 }<|endoftext|>


<commit_before>(function (custom) {
    /**
     * Collect visual elements from a page and feed the size back in the
     * format for Visual Metrics.
     */

    const elementByType = {};
    const areaByType = {};
    const imageTags = [].slice.call(document.body.getElementsByTagName('img'));
    const h1Tags = [].slice.call(document.body.getElementsByTagName('h1'));

    // When we feed options from the CLI it can be a String or an
    // Array with Strings. Make it easy to treat everything the same.
    function toArray(arrayLike) {
        if (arrayLike === undefined || arrayLike === null) {
            return [];
        }
        if (Array.isArray(arrayLike)) {
            return arrayLike;
        }
        return [arrayLike];
    }

    function isLargest(type, area) {
        if (!areaByType[type]) {
            return true;
        } else return areaByType[type] < area;
    }

    function isElementPartlyInViewportAndVisible (el) {
        const rect = el.getBoundingClientRect();
        return !(rect.bottom < 0 || rect.right < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight || rect.height === 0)
    }

    function visibleArea(el) {
        const rect = el.getBoundingClientRect();
        const viewportWidth = document.documentElement.clientWidth;
        const viewportHeight =  document.documentElement.clientHeight;

        // TODO make this more readable
        const width = rect.left < 0 ? rect.width + rect.left : (viewportWidth < rect.left + rect.width) ? viewportWidth  - rect.left : rect.width;
        const height = rect.top < 0 ?  rect.height + rect.top : (viewportHeight < rect.top + rect.height) ? viewportHeight - rect.top : rect.height;

        return width * height;
      }

    function keepLargestElementByType(type, element) {
        const area = visibleArea(element);
        if (isLargest(type, area)) {
            const filename = element.src ? element.src.substring(element.src.lastIndexOf('/') + 1) : undefined;
            const rect = element.getBoundingClientRect();
            elementByType[type] = {
                name: type,
                x: Math.round(rect.left),
                y: Math.round(rect.top),
                width: Math.round(rect.width),
                height: Math.round(rect.height),
                filename
            };
            areaByType[type] = area;
        }
    }

    if (custom) {
        // Input could be a String or an Array of Strings so convert it
        const customArray = toArray(custom);
        for (const nameAndSelector of customArray) {
            const parts = nameAndSelector.split(':');
            const type = parts[0];
            const selector = parts[1];
            const element = document.body.querySelector(selector);
            try {
                 if (isElementPartlyInViewportAndVisible(element)) {
                     keepLargestElementByType(type, element);
                 }
            } catch (e) {
                console.log('Could not find matching element for selector:' + selector + ' using document.body.querySelector. Do that element exist on the page?');
            }
        }
    }

    imageTags.forEach(function (element) {
        if (isElementPartlyInViewportAndVisible(element)) {
            keepLargestElementByType('LargestImage', element);
        }
    });

    h1Tags.forEach(function (element) {
        if (isElementPartlyInViewportAndVisible(element)) {
            keepLargestElementByType('Heading', element);
        }
    });

    // We need to follow the standard for VisualMetrics
    return {
        viewport: {
            width: document.documentElement.clientWidth,
            height: document.documentElement.clientHeight
        },
        // "heroes" :D https://github.com/sitespeedio/logo/blob/master/png/heroes/Pippi-Sitespeed.io.png
        heroes: Object.keys(elementByType).map(function (type) {
            return elementByType[type];
        })
    };
})(arguments[arguments.length - 1]);<commit_msg>Automatically pickup element timings (#841)<commit_after>(function(custom) {
  /**
   * Collect visual elements from a page and feed the size back in the
   * format for Visual Metrics.
   */

  const elementByType = {};
  const areaByType = {};
  const imageTags = [].slice.call(document.body.getElementsByTagName('img'));
  const h1Tags = [].slice.call(document.body.getElementsByTagName('h1'));
  const elementTimings = [].slice.call(
    document.querySelectorAll('[elementtiming]')
  );

  // When we feed options from the CLI it can be a String or an
  // Array with Strings. Make it easy to treat everything the same.
  function toArray(arrayLike) {
    if (arrayLike === undefined || arrayLike === null) {
      return [];
    }
    if (Array.isArray(arrayLike)) {
      return arrayLike;
    }
    return [arrayLike];
  }

  function isLargest(type, area) {
    if (!areaByType[type]) {
      return true;
    } else return areaByType[type] < area;
  }

  function isElementPartlyInViewportAndVisible(el) {
    const rect = el.getBoundingClientRect();
    return !(
      rect.bottom < 0 ||
      rect.right < 0 ||
      rect.left > window.innerWidth ||
      rect.top > window.innerHeight ||
      rect.height === 0
    );
  }

  function visibleArea(el) {
    const rect = el.getBoundingClientRect();
    const viewportWidth = document.documentElement.clientWidth;
    const viewportHeight = document.documentElement.clientHeight;

    // TODO make this more readable
    const width =
      rect.left < 0
        ? rect.width + rect.left
        : viewportWidth < rect.left + rect.width
        ? viewportWidth - rect.left
        : rect.width;
    const height =
      rect.top < 0
        ? rect.height + rect.top
        : viewportHeight < rect.top + rect.height
        ? viewportHeight - rect.top
        : rect.height;

    return width * height;
  }

  function keepLargestElementByType(type, element) {
    const area = visibleArea(element);
    if (isLargest(type, area)) {
      const filename = element.src
        ? element.src.substring(element.src.lastIndexOf('/') + 1)
        : undefined;
      const rect = element.getBoundingClientRect();
      elementByType[type] = {
        name: type,
        x: Math.round(rect.left),
        y: Math.round(rect.top),
        width: Math.round(rect.width),
        height: Math.round(rect.height),
        filename
      };
      areaByType[type] = area;
    }
  }

  if (custom) {
    // Input could be a String or an Array of Strings so convert it
    const customArray = toArray(custom);
    for (const nameAndSelector of customArray) {
      const parts = nameAndSelector.split(':');
      const type = parts[0];
      const selector = parts[1];
      const element = document.body.querySelector(selector);
      try {
        if (isElementPartlyInViewportAndVisible(element)) {
          keepLargestElementByType(type, element);
        }
      } catch (e) {
        console.log(
          'Could not find matching element for selector:' +
            selector +
            ' using document.body.querySelector. Do that element exist on the page?'
        );
      }
    }
  }

  imageTags.forEach(function(element) {
    if (isElementPartlyInViewportAndVisible(element)) {
      keepLargestElementByType('LargestImage', element);
    }
  });

  h1Tags.forEach(function(element) {
    if (isElementPartlyInViewportAndVisible(element)) {
      keepLargestElementByType('Heading', element);
    }
  });

  elementTimings.forEach(function(element) {
    if (isElementPartlyInViewportAndVisible(element)) {
      keepLargestElementByType(element.getAttribute('elementtiming'), element);
    }
  });

  // We need to follow the standard for VisualMetrics
  return {
    viewport: {
      width: document.documentElement.clientWidth,
      height: document.documentElement.clientHeight
    },
    // "heroes" :D https://github.com/sitespeedio/logo/blob/master/png/heroes/Pippi-Sitespeed.io.png
    heroes: Object.keys(elementByType).map(function(type) {
      return elementByType[type];
    })
  };
})(arguments[arguments.length - 1]);
<|endoftext|>


<commit_before>(function () {
  var HOME_URL = 'http://www.senscritique.com';
  var NOTIFICATIONS_URL = 'http://www.senscritique.com/notifications';

  // XHR helper function
  var xhr = function () {
    var xhr = new XMLHttpRequest();
    return function(method, url, callback) {
      xhr.onreadystatechange = function () {
        // request finished and response is ready
        if (xhr.readyState === 4) {
          if (xhr.status !== 200) {
            callback(false);
          }
          callback(xhr.responseText);
        }
      };
      xhr.open(method, url);
      xhr.send();
    };
  }();

  // main function
  window.NotificationsCount = function (callback) {
    var tmpDom = document.createElement('div');

    xhr('GET', HOME_URL, function (data) {
      var notifElem, countElem;
      tmpDom.innerHTML = data;

      // no data
      if (data === false) {
        callback(false);
      }

      notifElem = tmpDom.querySelector('a[href="/notifications"].lahead-subnav-link');
      if (notifElem) {
        countElem = tmpDom.querySelector('span.lahead-user-notify');
        if (countElem) {
          callback(countElem.textContent);
        } else {
          callback('0');
        }
      }
      else {
        callback(false);
      }
    });
  };

  // badge renderer
  function render(badge, color, title) {
    chrome.browserAction.setBadgeText({
      text: badge
    });
    chrome.browserAction.setBadgeBackgroundColor({
      color: color
    });
    chrome.browserAction.setTitle({
      title: title
    });
  }

  // update badge
  function update() {
    NotificationsCount(function (count) {
      if (count !== false) {
        //console.log(count);
        render((count !== '0' ? count : ''), [208, 0, 24, 255], chrome.i18n.getMessage('browserActionDefaultTitle', count));
      } else {
        render('?', [190, 190, 190, 230], chrome.i18n.getMessage('browserActionErrorTitle'));
      }
    });
  }

  // Chrome alarm
  chrome.alarms.create({periodInMinutes: 1});
  chrome.alarms.onAlarm.addListener(update);

  // browser action
  chrome.browserAction.onClicked.addListener(function () {
    chrome.tabs.create({
      url: NOTIFICATIONS_URL
    });
    update();
  });

  update();
})();<commit_msg>Update for SC v3<commit_after>(function () {
  var HOME_URL = 'http://www.senscritique.com';
  var NOTIFICATIONS_URL = 'http://www.senscritique.com/notifications';

  // XHR helper function
  var xhr = function () {
    var xhr = new XMLHttpRequest();
    return function(method, url, callback) {
      xhr.onreadystatechange = function () {
        // request finished and response is ready
        if (xhr.readyState === 4) {
          if (xhr.status !== 200) {
            callback(false);
          }
          callback(xhr.responseText);
        }
      };
      xhr.open(method, url);
      xhr.send();
    };
  }();

  // main function
  window.NotificationsCount = function (callback) {
    var tmpDom = document.createElement('div');

    xhr('GET', HOME_URL, function (data) {
      var notifElem, countElem;
      tmpDom.innerHTML = data;

      // no data
      if (data === false) {
        callback(false);
      }

      notifElem = tmpDom.querySelector('a[href="/notifications"].lahe-notifications-center');
      if (notifElem) {
        countElem = tmpDom.querySelector('span.lahe-notifications-count');
        if (countElem) {
          callback(countElem.textContent);
        } else {
          callback('0');
        }
      }
      else {
        callback(false);
      }
    });
  };

  // badge renderer
  function render(badge, color, title) {
    chrome.browserAction.setBadgeText({
      text: badge
    });
    chrome.browserAction.setBadgeBackgroundColor({
      color: color
    });
    chrome.browserAction.setTitle({
      title: title
    });
  }

  // update badge
  function update() {
    NotificationsCount(function (count) {
      if (count !== false) {
        //console.log(count);
        render((count !== '0' ? count : ''), [208, 0, 24, 255], chrome.i18n.getMessage('browserActionDefaultTitle', count));
      } else {
        render('?', [190, 190, 190, 230], chrome.i18n.getMessage('browserActionErrorTitle'));
      }
    });
  }

  // Chrome alarm
  chrome.alarms.create({periodInMinutes: 1});
  chrome.alarms.onAlarm.addListener(update);

  // browser action
  chrome.browserAction.onClicked.addListener(function () {
    chrome.tabs.create({
      url: NOTIFICATIONS_URL
    });
    update();
  });

  update();
})();<|endoftext|>