<commit_before>//Dont change it
requirejs(['ext_editor_1', 'jquery_190', 'raphael_210'],
    function (ext, $, TableComponent) {

        var cur_slide = {};

        ext.set_start_game(function (this_e) {
        });

        ext.set_process_in(function (this_e, data) {
            cur_slide["in"] = data[0];
        });

        ext.set_process_out(function (this_e, data) {
            cur_slide["out"] = data[0];
        });

        ext.set_process_ext(function (this_e, data) {
            cur_slide.ext = data;
            this_e.addAnimationSlide(cur_slide);
            cur_slide = {};
        });

        ext.set_process_err(function (this_e, data) {
            cur_slide['error'] = data[0];
            this_e.addAnimationSlide(cur_slide);
            cur_slide = {};
        });

        ext.set_animate_success_slide(function (this_e, options) {
            var $h = $(this_e.setHtmlSlide('

'));
            this_e.setAnimationHeight(115);
        });

        ext.set_animate_slide(function (this_e, data, options) {
            var $content = $(this_e.setHtmlSlide(ext.get_template('animation'))).find('.animation-content');
            if (!data) {
                console.log("data is undefined");
                return false;
            }

            //YOUR FUNCTION NAME
            var fname = 'place_queens';

            if (data.ext && data.ext.show) {
                var checkioInputStr = fname + "(" + data.ext.show + ")";
            }
            else {
                checkioInputStr = fname + '({"b1", "c4", "d6", "e8"})';
            }

            var failError = function (dError) {
                $content.find('.call').html('Fail: ' + checkioInputStr);
                $content.find('.output').html(dError.replace(/\n/g, ","));

                $content.find('.output').addClass('error');
                $content.find('.call').addClass('error');
                $content.find('.answer').remove();
                $content.find('.explanation').remove();
                this_e.setAnimationHeight($content.height() + 60);
            };

            if (data.error) {
                failError(data.error);
                return false;
            }

            if (data.ext && data.ext.inspector_fail) {
                failError(data.ext.inspector_result_addon);
                return false;
            }

            var checkioInput = data.in;
            var rightResult = data.ext["answer"];
            var userResult = data.out[0];
            var userResultShow = data.out[1];
            var result = data.ext["result"];
            var resultAddon = data.ext["result_addon"];
            var resultCode = resultAddon[0];
            var resultText = resultAddon[1];
            var threats = resultAddon[2];

            //if you need additional info from tests (if exists)
            var explanation = data.ext["explanation"];

            $content.find('.output').html(' Your result: ' + userResultShow);

            if (!result) {
                $content.find('.call').html('Fail: ' + checkioInputStr);
                $content.find('.answer').html(resultText);
                $content.find('.answer').addClass('error');
                $content.find('.output').addClass('error');
                $content.find('.call').addClass('error');
            }
            else {
                $content.find('.call').html('Pass: ' + checkioInputStr);
                $content.find('.answer').remove();
            }

            var canvas = new ChessCanvas($content.find(".explanation")[0]);
            canvas.prepare(checkioInput);

            this_e.setAnimationHeight($content.height() + 60);

        });

        //This is for Tryit (but not necessary)
//        var $tryit;
//        ext.set_console_process_ret(function (this_e, ret) {
//            $tryit.find(".checkio-result").html("Result
" + ret);
//        });
//
//        ext.set_generate_animation_panel(function (this_e) {
//            $tryit = $(this_e.setHtmlTryIt(ext.get_template('tryit'))).find('.tryit-content');
//            $tryit.find('.bn-check').click(function (e) {
//                e.preventDefault();
//                this_e.sendToConsoleCheckiO("something");
//            });
//        });

        function ChessCanvas(dom) {

            var colorOrange4 = "#F0801A";
            var colorOrange3 = "#FA8F00";
            var colorOrange2 = "#FAA600";
            var colorOrange1 = "#FABA00";

            var colorBlue4 = "#294270";
            var colorBlue3 = "#006CA9";
            var colorBlue2 = "#65A1CF";
            var colorBlue1 = "#8FC7ED";

            var colorGrey4 = "#737370";
            var colorGrey3 = "#9D9E9E";
            var colorGrey2 = "#C5C6C6";
            var colorGrey1 = "#EBEDED";

            var colorWhite = "#FFFFFF";

            var padding = 10;
            var cell = 40;

            var figures;

            var size = padding * 2 + cell * 9;
            var paper = Raphael(dom, size, size);

            var attrBoard = {"stroke": colorBlue4, "stroke-width": 3};
            var attrBlack = {"fill": colorBlue2, "stroke-width": 0};
            var attrWhite = {"fill": colorGrey1, "stroke-width": 0};
            var attrQueen = {"stroke": colorBlue4, "font-family": "Roboto", "font-size": cell * 0.8};
            var attrText = {"stroke": colorBlue4, "font-family": "Roboto", "font-size": cell * 0.8, "font-weight": "bold"};

            var rows = "12345678";
            var cols = "abcdefgh";

            this.place_queen = function(coor, full) {
                var r = rows.indexOf(coor[1]);
                var c = cols.indexOf(coor[0]);
                paper.text(padding + cell * 1.5 + c * cell, size - padding - cell * 1.5 - cell * r,
                    full ? "♛" : "♕").attr(attrQueen);
            };

            this.prepare = function(placed) {
                for (var i = 0; i < 8; i++) {
                    paper.text(padding + cell / 2, size - padding - cell * i - cell * 1.5, rows[i]).attr(attrText);
                    paper.text(padding + cell * 1.5 + cell * i, size - padding - cell / 2, cols[i]).attr(attrText);
                    for (var j = 0; j < 8; j++) {
                        paper.rect(padding + cell + cell * i, padding + cell * j, cell, cell).attr(
                            (i + j) % 2 === 1 ? attrBlack : attrWhite);
                    }
                }
                paper.rect(padding + cell, padding, cell * 8, cell * 8).attr(attrBoard);
                for (i = 0; i < placed.length; i++) {
                    this.place_queen(placed[i], true);
                }
            }

        }

    }
);
<commit_msg>graphic<commit_after>//Dont change it
requirejs(['ext_editor_1', 'jquery_190', 'raphael_210'],
    function (ext, $, TableComponent) {

        var cur_slide = {};

        ext.set_start_game(function (this_e) {
        });

        ext.set_process_in(function (this_e, data) {
            cur_slide["in"] = data[0];
        });

        ext.set_process_out(function (this_e, data) {
            cur_slide["out"] = data[0];
        });

        ext.set_process_ext(function (this_e, data) {
            cur_slide.ext = data;
            this_e.addAnimationSlide(cur_slide);
            cur_slide = {};
        });

        ext.set_process_err(function (this_e, data) {
            cur_slide['error'] = data[0];
            this_e.addAnimationSlide(cur_slide);
            cur_slide = {};
        });

        ext.set_animate_success_slide(function (this_e, options) {
            var $h = $(this_e.setHtmlSlide('

'));
            this_e.setAnimationHeight(115);
        });

        ext.set_animate_slide(function (this_e, data, options) {
            var $content = $(this_e.setHtmlSlide(ext.get_template('animation'))).find('.animation-content');
            if (!data) {
                console.log("data is undefined");
                return false;
            }

            //YOUR FUNCTION NAME
            var fname = 'place_queens';

            if (data.ext && data.ext.show) {
                var checkioInputStr = fname + "(" + data.ext.show + ")";
            }
            else {
                checkioInputStr = fname + '({"b1", "c4", "d6", "e8"})';
            }

            var failError = function (dError) {
                $content.find('.call').html('Fail: ' + checkioInputStr);
                $content.find('.output').html(dError.replace(/\n/g, ","));

                $content.find('.output').addClass('error');
                $content.find('.call').addClass('error');
                $content.find('.answer').remove();
                $content.find('.explanation').remove();
                this_e.setAnimationHeight($content.height() + 60);
            };

            if (data.error) {
                failError(data.error);
                return false;
            }

            if (data.ext && data.ext.inspector_fail) {
                failError(data.ext.inspector_result_addon);
                return false;
            }

            var checkioInput = data.in;
            var rightResult = data.ext["answer"];
            var userResult = data.out[0];
            var userResultShow = data.out[1];
            var result = data.ext["result"];
            var resultAddon = data.ext["result_addon"];
            var resultCode = resultAddon[0];
            var resultText = resultAddon[1];
            var threats = resultAddon[2];

            //if you need additional info from tests (if exists)
            var explanation = data.ext["explanation"];

            $content.find('.output').html(' Your result: ' + userResultShow);

            if (!result) {
                $content.find('.call').html('Fail: ' + checkioInputStr);
                $content.find('.answer').html(resultText);
                $content.find('.answer').addClass('error');
                $content.find('.output').addClass('error');
                $content.find('.call').addClass('error');
            }
            else {
                $content.find('.call').html('Pass: ' + checkioInputStr);
                $content.find('.answer').remove();
            }

            var canvas = new ChessCanvas($content.find(".explanation")[0]);
            canvas.prepare(checkioInput);
            if (resultCode > 1) {
                canvas.supposed(userResult);
                canvas.drawThreats(threats);
            }

            this_e.setAnimationHeight($content.height() + 60);

        });

        //This is for Tryit (but not necessary)
//        var $tryit;
//        ext.set_console_process_ret(function (this_e, ret) {
//            $tryit.find(".checkio-result").html("Result
" + ret);
//        });
//
//        ext.set_generate_animation_panel(function (this_e) {
//            $tryit = $(this_e.setHtmlTryIt(ext.get_template('tryit'))).find('.tryit-content');
//            $tryit.find('.bn-check').click(function (e) {
//                e.preventDefault();
//                this_e.sendToConsoleCheckiO("something");
//            });
//        });

        function ChessCanvas(dom) {

            var colorOrange4 = "#F0801A";
            var colorOrange3 = "#FA8F00";
            var colorOrange2 = "#FAA600";
            var colorOrange1 = "#FABA00";

            var colorBlue4 = "#294270";
            var colorBlue3 = "#006CA9";
            var colorBlue2 = "#65A1CF";
            var colorBlue1 = "#8FC7ED";

            var colorGrey4 = "#737370";
            var colorGrey3 = "#9D9E9E";
            var colorGrey2 = "#C5C6C6";
            var colorGrey1 = "#EBEDED";

            var colorWhite = "#FFFFFF";

            var padding = 10;
            var cell = 40;

            var figures = [];

            var size = padding * 2 + cell * 9;
            var paper = Raphael(dom, size, size);

            var figSet = paper.set();

            var attrBoard = {"stroke": colorBlue4, "stroke-width": 4};
            var attrBlack = {"fill": colorBlue2, "stroke-width": 0};
            var attrWhite = {"fill": colorGrey1, "stroke-width": 0};
            var attrQueen = {"stroke": colorBlue4, "font-family": "Roboto", "font-size": cell * 0.8};
            var attrText = {"stroke": colorBlue4, "font-family": "Roboto", "font-size": cell * 0.8, "font-weight": "bold"};
            var attrThreat = {"stroke": colorOrange4, "stroke-width": 4, "stroke-linecap": "round"};

            var rows = "12345678";
            var cols = "abcdefgh";

            this.place_queen = function(coor, full) {
                var r = rows.indexOf(coor[1]);
                var c = cols.indexOf(coor[0]);
                return paper.text(padding + cell * 1.5 + c * cell, size - padding - cell * 1.5 - cell * r,
                    full ? "♛" : "♕").attr(attrQueen);
            };

            this.prepare = function(placed) {
                for (var i = 0; i < 8; i++) {
                    paper.text(padding + cell / 2, size - padding - cell * i - cell * 1.5, rows[i]).attr(attrText);
                    paper.text(padding + cell * 1.5 + cell * i, size - padding - cell / 2, cols[i]).attr(attrText);
                    for (var j = 0; j < 8; j++) {
                        paper.rect(padding + cell + cell * i, padding + cell * j, cell, cell).attr(
                            (i + j) % 2 === 1 ? attrBlack : attrWhite);
                    }
                }
                paper.rect(padding + cell, padding, cell * 8, cell * 8).attr(attrBoard);
                for (i = 0; i < placed.length; i++) {
                    figures.push(placed[i]);
                    figSet.push(this.place_queen(placed[i], true));
                }
            };

            this.supposed = function(userFigures) {
                for (var i = 0; i < userFigures.length; i++) {
                    if (figures.indexOf(userFigures[i]) === -1) {
                        figSet.push(this.place_queen(userFigures[i], false));
                    }
                }
            };

            this.drawThreats = function(lines) {
                for (var i = 0; i < lines.length; i++) {
                    var r1 = rows.indexOf(lines[i][0][1]);
                    var c1 = cols.indexOf(lines[i][0][0]);
                    var r2 = rows.indexOf(lines[i][1][1]);
                    var c2 = cols.indexOf(lines[i][1][0]);
                    paper.path([
                        ["M", padding + cell * 1.5 + c1 * cell, size - padding - cell * 1.5 - cell * r1],
                        ["L", padding + cell * 1.5 + c2 * cell, size - padding - cell * 1.5 - cell * r2]]
                    ).attr(attrThreat);

                }
                figSet.toFront();
            }

        }

    }
);
<|endoftext|>


<commit_before>svgEditor.readLang({
	lang: "fr",
	dir : "ltr",
	common: {
		"ok": "OK",
		"cancel": "Annuler",
		"key_backspace": "Suppr.",
		"key_del": "Retour Arr.",
		"key_down": "Bas",
		"key_up": "Haut",
		"more_opts": "More Options",
		"url": "URL",
		"width": "Width",
		"height": "Height"
	},
	misc: {
		"powered_by": "Powered by"
	},
	ui: {
		"toggle_stroke_tools": "Montrer/Cacher plus d'outils de Contour",
		"palette_info": "Cliquer pour changer la couleur de remplissage, Shift-Clic pour changer la couleur de contour",
		"zoom_level": "Changer le niveau de zoom",
		"panel_drag": "Drag left/right to resize side panel"
	},
	properties: {
		"id": "Identifier l'élément",
		"fill_color": "Changer la couleur de remplissage",
		"stroke_color": "Changer la couleur du contour",
		"stroke_style": "Changer le style du contour",
		"stroke_width": "Changer la largeur du contour de 1, Shift-Click pour changer la largeur de 0.1",
		"pos_x": "Changer la position horizontale X",
		"pos_y": "Changer la position verticale Y",
		"linecap_butt": "Terminaison : Sur le nœud",
		"linecap_round": "Terminaison : Arrondie",
		"linecap_square": "Terminaison : Carrée",
		"linejoin_bevel": "Raccord : Biseauté",
		"linejoin_miter": "Raccord : Droit",
		"linejoin_round": "Raccord : Arrondi",
		"angle": "Changer l'angle de rotation",
		"blur": "Changer la valeur du flou gaussien",
		"opacity": "Changer l'opacité de l'élément sélectionné",
		"circle_cx": "Changer la position horizontale cx du cercle",
		"circle_cy": "Changer la position verticale cy du cercle",
		"circle_r": "Changer le rayon du cercle",
		"ellipse_cx": "Changer la position horizontale cx de l'ellipse",
		"ellipse_cy": "Changer la position verticale cy de l'ellipse",
		"ellipse_rx": "Changer le rayon horizontal x de l'ellipse",
		"ellipse_ry": "Changer le rayon vertical y de l'ellipse",
		"line_x1": "Changer la position horizontale x de début de la ligne",
		"line_x2": "Changer la position horizontale x de fin de la ligne",
		"line_y1": "Changer la position verticale y de début de la ligne",
		"line_y2": "Changer la position verticale y de fin de la ligne",
		"rect_height": "Changer la hauteur du rectangle",
		"rect_width": "Changer la largeur du rectangle",
		"corner_radius": "Changer le rayon des coins du rectangle",
		"image_width": "Changer la largeur de l'image",
		"image_height": "Changer la hauteur de l'image",
		"image_url": "Modifier l'URL",
		"node_x": "Changer la positon horizontale x du nœud",
		"node_y": "Changer la position verticale y du nœud",
		"seg_type": "Changer le type du Segment",
		"straight_segments": "Droit",
		"curve_segments": "Courbe",
		"text_contents": "Changer le contenu du texte",
		"font_family": "Changer la famille de police",
		"font_size": "Changer la taille de la police",
		"bold": "Texte en gras",
		"italic": "Texte en italique"
	},
	tools: {
		"main_menu": "Menu principal",
		"bkgnd_color_opac": "Changer la couleur d'arrière-plan / l'opacité",
		"connector_no_arrow": "Sans flèches",
		"fitToContent": "Ajuster au contenu",
		"fit_to_all": "Ajuster au contenu de tous les calques",
		"fit_to_canvas": "Ajuster au canevas",
		"fit_to_layer_content": "Ajuster au contenu du calque",
		"fit_to_sel": "Ajuster à la sélection",
		"align_relative_to": "Aligner par rapport à ...",
		"relativeTo": "Relativement à:",
		"Page": "Page",
		"largest_object": "Plus gros objet",
		"selected_objects": "Objets sélectionnés",
		"smallest_object": "Plus petit objet",
		"new_doc": "Nouvelle image",
		"open_doc": "Ouvrir une image",
		"export_png": "Exporter au format PNG",
		"save_doc": "Enregistrer l'image",
		"import_doc": "Importer un objet SVG",
		"align_to_page": "Aligner l'élément relativement à la Page",
		"align_bottom": "Aligner le bas des objets",
		"align_center": "Centrer verticalement",
		"align_left": "Aligner les côtés gauches",
		"align_middle": "Centrer horizontalement",
		"align_right": "Aligner les côtés droits",
		"align_top": "Aligner le haut des objets",
		"mode_select": "Outil de sélection",
		"mode_fhpath": "Crayon à main levée",
		"mode_line": "Tracer des lignes",
		"mode_connect": "Connecter deux objets",
		"mode_rect": "Rectangle Tool",
		"mode_square": "Square Tool",
		"mode_fhrect": "Rectangle main levée",
		"mode_ellipse": "Ellipse",
		"mode_circle": "Cercle",
		"mode_fhellipse": "Ellipse main levée",
		"mode_path": "Outil Chemin",
		"mode_shapelib": "Shape library",
		"mode_text": "Outil Texte",
		"mode_image": "Outil Image",
		"mode_zoom": "Zoom",
		"mode_eyedropper": "Outil Pipette",
		"no_embed": "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",
		"undo": "Annuler l'action",
		"redo": "Refaire l'action",
		"tool_source": "Modifier la source",
		"wireframe_mode": "Mode Fil de Fer",
		"toggle_grid": "Show/Hide Grid",
		"clone": "Clone Element(s)",
		"del": "Delete Element(s)",
		"group": "Grouper les éléments",
		"make_link": "Make (hyper)link",
		"set_link_url": "Set link URL (leave empty to remove)",
		"to_path": "Convertir en chemin",
		"reorient_path": "Réorienter le chemin",
		"ungroup": "Dégrouper les éléments",
		"docprops": "Propriétés du document",
		"imagelib": "Image Library",
		"move_bottom": "Déplacer vers le bas",
		"move_top": "Déplacer vers le haut",
		"node_clone": "Cloner le nœud",
		"node_delete": "Supprimer le nœud",
		"node_link": "Rendre les points de contrôle solidaires",
		"add_subpath": "Ajouter un sous-chemin",
		"openclose_path": "Ouvrir/Fermer sous-chemin",
		"source_save": "Appliquer Modifications",
		"cut": "Cut",
		"copy": "Copy",
		"paste": "Paste",
		"paste_in_place": "Paste in Place",
		"Retour Arr.": "Delete",
		"group": "Group",
		"move_front": "Bring to Front",
		"move_up": "Bring Forward",
		"move_down": "Send Backward",
		"move_back": "Send to Back"
	},
	layers: {
		"layer":"Calque",
		"layers": "Layers",
		"del": "Supprimer le calque",
		"move_down": "Descendre le calque",
		"new": "Nouveau calque",
		"rename": "Renommer le calque",
		"move_up": "Monter le calque",
		"dupe": "Duplicate Layer",
		"merge_down": "Merge Down",
		"merge_all": "Merge All",
		"move_elems_to": "Déplacer éléments vers:",
		"move_selected": "Déplacer les éléments sélectionnés vers un autre calque"
	},
	config: {
		"image_props": "Propriétés de l'Image",
		"doc_title": "Titre",
		"doc_dims": "Dimensions du canevas",
		"included_images": "Images incorporées",
		"image_opt_embed": "Incorporer les images en tant que données (fichiers locaux)",
		"image_opt_ref": "Utiliser la référence des images ",
		"editor_prefs": "Préférences de l'Éditeur",
		"icon_size": "Taille des icônes",
		"language": "Langue",
		"background": "Toile de fond de l'Éditeur",
		"editor_img_url": "Image URL",
		"editor_bg_note": "Note: La toile de fond n'est pas sauvegardée avec l'image.",
		"icon_large": "Grande",
		"icon_medium": "Moyenne",
		"icon_small": "Petite",
		"icon_xlarge": "Super-Grande",
		"select_predefined": "Sélectionner prédéfinis:",
		"units_and_rulers": "Units & Rulers",
		"show_rulers": "Show rulers",
		"base_unit": "Base Unit:",
		"grid": "Grid",
		"snapping_onoff": "Snapping on/off",
		"snapping_stepsize": "Snapping Step-Size:"
	},
	shape_cats: {
		"basic": "Basic",
		"object": "Objects",
		"symbol": "Symbols",
		"arrow": "Arrows",
		"flowchart": "Flowchart",
		"animal": "Animals",
		"game": "Cards & Chess",
		"dialog_balloon": "Dialog balloons",
		"electronics": "Electronics",
		"math": "Mathematical",
		"music": "Music",
		"misc": "Miscellaneous",
		"raphael_1": "raphaeljs.com set 1",
		"raphael_2": "raphaeljs.com set 2"
	},
	imagelib: {
		"select_lib": "Select an image library",
		"show_list": "Show library list",
		"import_single": "Import single",
		"import_multi": "Import multiple",
		"open": "Open as new document"
	},
	notification: {
		"invalidAttrValGiven":"Valeur fournie invalide",
		"noContentToFitTo":"Il n'y a pas de contenu auquel ajuster",
		"dupeLayerName":"Il existe déjà un calque de ce nom !",
		"enterUniqueLayerName":"Veuillez entrer un nom (unique) pour le calque",
		"enterNewLayerName":"Veuillez entrer le nouveau nom du calque",
		"layerHasThatName":"Le calque porte déjà ce nom",
		"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é !",
		"QwantToOpen":"Do you want to open a new file?\nThis will also erase your undo history!",
		"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 ?",
		"featNotSupported":"Fonction non supportée",
		"enterNewImgURL":"Entrer la nouvelle URL de l'image",
		"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.",
		"loadingImage":"Chargement de l'image, veuillez patienter...",
		"saveFromBrowser": "Selectionner \"Enregistrer sous...\" dans votre navigateur pour sauvegarder l'image en tant que fichier %s.",
		"noteTheseIssues": "Notez également les problèmes suivants : ",
		"unsavedChanges": "There are unsaved changes.",
		"enterNewLinkURL": "Enter the new hyperlink URL",
		"errorLoadingSVG": "Error: Unable to load SVG data",
		"URLloadFail": "Unable to load from URL",
		"retrieving": "Retrieving \"%s\"..."
	}
});<commit_msg>Testing translation via web interface to update documentation accordingly<commit_after>svgEditor.readLang({
	lang: "fr",
	dir : "ltr",
	common: {
		"ok": "OK",
		"cancel": "Annuler",
		"key_backspace": "Suppr.",
		"key_del": "Retour Arr.",
		"key_down": "Bas",
		"key_up": "Haut",
		"more_opts": "More Options",
		"url": "URL",
		"width": "Width",
		"height": "Height"
	},
	misc: {
		"powered_by": "Powered by"
	},
	ui: {
		"toggle_stroke_tools": "Montrer/Cacher plus d'outils de Contour",
		"palette_info": "Cliquer pour changer la couleur de remplissage, Shift-Clic pour changer la couleur de contour",
		"zoom_level": "Changer le niveau de zoom",
		"panel_drag": "Drag left/right to resize side panel"
	},
	properties: {
		"id": "Identifier l'élément",
		"fill_color": "Changer la couleur de remplissage",
		"stroke_color": "Changer la couleur du contour",
		"stroke_style": "Changer le style du contour",
		"stroke_width": "Changer la largeur du contour de 1, Shift-Click pour changer la largeur de 0.1",
		"pos_x": "Changer la position horizontale X",
		"pos_y": "Changer la position verticale Y",
		"linecap_butt": "Terminaison : Sur le nœud",
		"linecap_round": "Terminaison : Arrondie",
		"linecap_square": "Terminaison : Carrée",
		"linejoin_bevel": "Raccord : Biseauté",
		"linejoin_miter": "Raccord : Droit",
		"linejoin_round": "Raccord : Arrondi",
		"angle": "Changer l'angle de rotation",
		"blur": "Changer la valeur du flou gaussien",
		"opacity": "Changer l'opacité de l'élément sélectionné",
		"circle_cx": "Changer la position horizontale cx du cercle",
		"circle_cy": "Changer la position verticale cy du cercle",
		"circle_r": "Changer le rayon du cercle",
		"ellipse_cx": "Changer la position horizontale cx de l'ellipse",
		"ellipse_cy": "Changer la position verticale cy de l'ellipse",
		"ellipse_rx": "Changer le rayon horizontal x de l'ellipse",
		"ellipse_ry": "Changer le rayon vertical y de l'ellipse",
		"line_x1": "Changer la position horizontale x de début de la ligne",
		"line_x2": "Changer la position horizontale x de fin de la ligne",
		"line_y1": "Changer la position verticale y de début de la ligne",
		"line_y2": "Changer la position verticale y de fin de la ligne",
		"rect_height": "Changer la hauteur du rectangle",
		"rect_width": "Changer la largeur du rectangle",
		"corner_radius": "Changer le rayon des coins du rectangle",
		"image_width": "Changer la largeur de l'image",
		"image_height": "Changer la hauteur de l'image",
		"image_url": "Modifier l'URL",
		"node_x": "Changer la positon horizontale x du nœud",
		"node_y": "Changer la position verticale y du nœud",
		"seg_type": "Changer le type du Segment",
		"straight_segments": "Droit",
		"curve_segments": "Courbe",
		"text_contents": "Changer le contenu du texte",
		"font_family": "Changer la famille de police",
		"font_size": "Changer la taille de la police",
		"bold": "Texte en gras",
		"italic": "Texte en italique"
	},
	tools: {
		"main_menu": "Menu principal",
		"bkgnd_color_opac": "Changer la couleur d'arrière-plan / l'opacité",
		"connector_no_arrow": "Sans flèches",
		"fitToContent": "Ajuster au contenu",
		"fit_to_all": "Ajuster au contenu de tous les calques",
		"fit_to_canvas": "Ajuster au canevas",
		"fit_to_layer_content": "Ajuster au contenu du calque",
		"fit_to_sel": "Ajuster à la sélection",
		"align_relative_to": "Aligner par rapport à ...",
		"relativeTo": "Relativement à:",
		"Page": "Page",
		"largest_object": "Plus gros objet",
		"selected_objects": "Objets sélectionnés",
		"smallest_object": "Plus petit objet",
		"new_doc": "Nouvelle image",
		"open_doc": "Ouvrir une image",
		"export_png": "Exporter au format PNG",
		"save_doc": "Enregistrer l'image",
		"import_doc": "Importer un objet SVG",
		"align_to_page": "Aligner l'élément relativement à la Page",
		"align_bottom": "Aligner le bas des objets",
		"align_center": "Centrer verticalement",
		"align_left": "Aligner les côtés gauches",
		"align_middle": "Centrer horizontalement",
		"align_right": "Aligner les côtés droits",
		"align_top": "Aligner le haut des objets",
		"mode_select": "Outil de sélection",
		"mode_fhpath": "Crayon à main levée",
		"mode_line": "Tracer des lignes",
		"mode_connect": "Connecter deux objets",
		"mode_rect": "Rectangle Tool",
		"mode_square": "Square Tool",
		"mode_fhrect": "Rectangle main levée",
		"mode_ellipse": "Ellipse",
		"mode_circle": "Cercle",
		"mode_fhellipse": "Ellipse main levée",
		"mode_path": "Outil Chemin",
		"mode_shapelib": "Shape library",
		"mode_text": "Outil Texte",
		"mode_image": "Outil Image",
		"mode_zoom": "Zoom",
		"mode_eyedropper": "Outil Pipette",
		"no_embed": "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",
		"undo": "Annuler l'action",
		"redo": "Refaire l'action",
		"tool_source": "Modifier la source",
		"wireframe_mode": "Mode Fil de Fer",
		"toggle_grid": "Show/Hide Grid",
		"clone": "Clone Element(s)",
		"del": "Delete Element(s)",
		"group": "Grouper les éléments",
		"make_link": "Make (hyper)link",
		"set_link_url": "Set link URL (leave empty to remove)",
		"to_path": "Convertir en chemin",
		"reorient_path": "Réorienter le chemin",
		"ungroup": "Dégrouper les éléments",
		"docprops": "Propriétés du document",
		"imagelib": "Image Library",
		"move_bottom": "Déplacer vers le bas",
		"move_top": "Déplacer vers le haut",
		"node_clone": "Cloner le nœud",
		"node_delete": "Supprimer le nœud",
		"node_link": "Rendre les points de contrôle solidaires",
		"add_subpath": "Ajouter un sous-chemin",
		"openclose_path": "Ouvrir/Fermer sous-chemin",
		"source_save": "Appliquer Modifications",
		"cut": "Cut",
		"copy": "Copy",
		"paste": "Paste",
		"paste_in_place": "Paste in Place",
		"Retour Arr.": "Delete",
		"group": "Group",
		"move_front": "Bring to Front",
		"move_up": "Bring Forward",
		"move_down": "Send Backward",
		"move_back": "Send to Back"
	},
	layers: {
		"layer":"Calque",
		"layers": "Layers",
		"del": "Supprimer le calque",
		"move_down": "Descendre le calque",
		"new": "Nouveau calque",
		"rename": "Renommer le calque",
		"move_up": "Monter le calque",
		"dupe": "Duplicate Layer",
		"merge_down": "Merge Down",
		"merge_all": "Merge All",
		"move_elems_to": "Déplacer éléments vers:",
		"move_selected": "Déplacer les éléments sélectionnés vers un autre calque"
	},
	config: {
		"image_props": "Propriétés de l'Image",
		"doc_title": "Titre",
		"doc_dims": "Dimensions du canevas",
		"included_images": "Images incorporées",
		"image_opt_embed": "Incorporer les images en tant que données (fichiers locaux)",
		"image_opt_ref": "Utiliser la référence des images ",
		"editor_prefs": "Préférences de l'Éditeur",
		"icon_size": "Taille des icônes",
		"language": "Langue",
		"background": "Toile de fond de l'Éditeur",
		"editor_img_url": "Image URL",
		"editor_bg_note": "Note: La toile de fond n'est pas sauvegardée avec l'image.",
		"icon_large": "Grande",
		"icon_medium": "Moyenne",
		"icon_small": "Petite",
		"icon_xlarge": "Super-Grande",
		"select_predefined": "Sélectionner prédéfinis:",
		"units_and_rulers": "Units & Rulers",
		"show_rulers": "Show rulers",
		"base_unit": "Base Unit:",
		"grid": "Grid",
		"snapping_onoff": "Snapping on/off",
		"snapping_stepsize": "Snapping Step-Size:"
	},
	shape_cats: {
		"basic": "Basic",
		"object": "Objects",
		"symbol": "Symbols",
		"arrow": "Arrows",
		"flowchart": "Flowchart",
		"animal": "Animals",
		"game": "Cards & Chess",
		"dialog_balloon": "Dialog balloons",
		"electronics": "Electronics",
		"math": "Mathematical",
		"music": "Music",
		"misc": "Miscellaneous",
		"raphael_1": "raphaeljs.com set 1",
		"raphael_2": "raphaeljs.com set 2"
	},
	imagelib: {
		"select_lib": "Select an image library",
		"show_list": "Show library list",
		"import_single": "Import single",
		"import_multi": "Import multiple",
		"open": "Open as new document"
	},
	notification: {
		"invalidAttrValGiven":"Valeur fournie invalide",
		"noContentToFitTo":"Il n'y a pas de contenu auquel ajuster",
		"dupeLayerName":"Il existe déjà un calque de ce nom !",
		"enterUniqueLayerName":"Veuillez entrer un nom (unique) pour le calque",
		"enterNewLayerName":"Veuillez entrer le nouveau nom du calque",
		"layerHasThatName":"Le calque porte déjà ce nom",
		"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é !",
		"QwantToOpen":"Do you want to open a new file?\nThis will also erase your undo history!",
		"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 ?",
		"featNotSupported":"Fonction non supportée",
		"enterNewImgURL":"Entrer la nouvelle URL de l'image",
		"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.",
		"loadingImage":"Chargement de l'image, veuillez patienter...",
		"saveFromBrowser": "Selectionner \"Enregistrer sous...\" dans votre navigateur pour sauvegarder l'image en tant que fichier %s.",
		"noteTheseIssues": "Notez également les problèmes suivants : ",
		"unsavedChanges": "Il y a des changements non sauvegardés.",
		"enterNewLinkURL": "Enter the new hyperlink URL",
		"errorLoadingSVG": "Error: Unable to load SVG data",
		"URLloadFail": "Unable to load from URL",
		"retrieving": "Retrieving \"%s\"..."
	}
});<|endoftext|>


<commit_before>/**
 * @classdesc
 * Base class for all the layers, defines common methods that all the layer classes share.
 * @class
 * @category layer
 * @abstract
 * @extends maptalks.Class
 * @mixes maptalks.Eventable
 * @mixes maptalks.Renderable
 */
Z.Layer=Z.Class.extend(/** @lends maptalks.Layer.prototype */{

    includes: Z.Eventable,

    /**
     * @property {Object}  [options=null] - base options of layer.
     * @property {Number}  [options.minZoom=-1] - the minimum zoom to display the layer, set to -1 to unlimit it.
     * @property {Number}  [options.maxZoom=-1] - the maximum zoom to display the layer, set to -1 to unlimit it.
     * @property {Boolean} [options.visible=true] - whether to display the layer.
     * @property {Number}  [options.opacity=1] - opacity of the layer, from 0 to 1.
     * @property {String}  [options.renderer=canvas] - renderer type. Don't change it if you are not sure about it. About renderer, see [TODO]{@link tutorial.renderer}.
     */
    options:{
        //最大最小可视范围, null表示不受限制
        'minZoom':null,
        'maxZoom':null,
        //图层是否可见
        'visible':true,
        'opacity': 1,
        'renderer' : 'canvas'
    },

     /**
     * load the tile layer, can't be overrided by sub-classes
     */
    load:function(){
        if (!this.getMap()) {return this;}
        this._initRenderer();
        var zIndex = this.getZIndex();
        if (!Z.Util.isNil(zIndex)) {
            this._renderer.setZIndex(zIndex);
        }
        if (this._prepareLoad()) {
            this._renderer.render();
        }
        return this;
    },

    /**
     * Get the layer id
     * @returns {String|Number} id
     */
    getId:function() {
        return this._id;
    },

    /**
     * Set a new id to the layer
     * @param {String|Number} id - new layer id
     * @return {maptalks.Layer} this
     * @fires maptalks.Layer#idchange
     */
    setId:function(id) {
        //TODO 设置id可能造成map无法找到layer
        var old = this._id;
        this._id = id;
        /**
         * idchange event.
         *
         * @event maptalks.Layer#idchange
         * @type {Object}
         * @property {String} type - idchange
         * @property {maptalks.Layer} target    - the layer fires the event
         * @property {String|Number} old        - value of the old id
         * @property {String|Number} new        - value of the new id
         */
        this.fire('idchange', {'old':old, 'new':id});
        return this;
    },

    /**
     * Adds itself to a map.
     * @param {maptalks.Map} map - map added to
     * @return {maptalks.Layer} this
     */
    addTo:function(map) {
        map.addLayer(this);
        return this;
    },

    /**
     * Set a z-index to the layer
     * @param {Number} zIndex - layer's z-index
     * @return {maptalks.Layer} this
     */
    setZIndex:function(zIndex) {
        this._zIndex = zIndex;
        if (this.map) {
            var layerList = this._getLayerList();
            this.map._sortLayersByZIndex(layerList);
        }
        if (this._renderer) {
            this._renderer.setZIndex(zIndex);
        }
        return this;
    },

    /**
     * Get the layer's z-index
     * @return {Number}
     */
    getZIndex:function() {
        return this._zIndex;
    },

    /**
     * If the layer is rendered by HTML5 Canvas 2d.
     * @return {Boolean}
     * @protected
     */
    isCanvasRender:function() {
        var renderer = this._getRenderer();
        if (renderer) {
            return renderer.isCanvasRender();
        }
        return false;
    },

    /**
     * Get the map that the layer added to
     * @returns {maptalks.Map}
     */
    getMap:function() {
        if (this.map) {
            return this.map;
        }
        return null;
    },

    /**
     * Brings the layer to the top of all the layers
     * @returns {maptalks.Layer} this
     */
    bringToFront:function() {
        var layers = this._getLayerList();
        if (!layers) {
            return this;
        }
        var topLayer = layers[layers.length-1];
        if (layers.length === 1 || topLayer === this) {
            return this;
        }
        var max = topLayer.getZIndex();
        this.setZIndex(max+1);
        return this;
    },

    /**
     * Brings the layer under the bottom of all the layers
     * @returns {maptalks.Layer} this
     */
    bringToBack:function(){
        var layers = this._getLayerList();
        if (!layers) {
            return this;
        }
        var bottomLayer = layers[0];
        if (layers.length === 1 || bottomLayer === this) {
            return this;
        }
        var min = bottomLayer.getZIndex();
        this.setZIndex(min-1);
        return this;
    },

    /**
     * Show the layer
     * @returns {maptalks.Layer} this
     */
    show:function() {
        if (!this.options['visible']) {
            this.options['visible'] = true;
            if (this._getRenderer()) {
                this._getRenderer().show();
            }
        }
        this.fire('show');
        return this;
    },

    /**
     * Hide the layer
     * @returns {maptalks.Layer} this
     */
    hide:function() {
        if (this.options['visible']) {
            this.options['visible'] = false;
            if (this._getRenderer()) {
                this._getRenderer().hide();
            }
        }
        this.fire('hide');
        return this;
    },

    isLoaded:function() {
        if (!this._renderer) {
            return false;
        }
        return this._renderer.isLoaded();
    },

    /**
     * Whether the layer is visible now.
     * @return {Boolean}
     */
    isVisible:function() {
        if (Z.Util.isNumber(this.options['opacity']) && this.options['opacity'] <= 0) {
            return false;
        }
        var map = this.getMap();
        if (map) {
            var zoom = map.getZoom();
            if ((!Z.Util.isNil(this.options['maxZoom']) && this.options['maxZoom'] < zoom)
                    || (!Z.Util.isNil(this.options['minZoom']) && this.options['minZoom'] > zoom)) {
                return false;
            }
        }

        if (Z.Util.isNil(this.options['visible'])) {
            this.options['visible'] = true;
        }
        return this.options['visible'];
    },

    /**
     * Remove itself from the map added to.
     * @returns {maptalks.Layer} this
     */
    remove:function() {
        if (this.map) {
            this.map.removeLayer(this);
        }
        return this;
    },

    /**
     * Get the mask geometry of the layer
     * @return {maptalks.Geometry}
     */
    getMask:function() {
        return this._mask;
    },

    /**
     * Set a mask geometry on the layer, only the area in the mask will be displayed.
     * @param {maptalks.Geometry} mask - mask geometry, can only be a Marker with vector symbol, a Polygon or a MultiPolygon
     * @returns {maptalks.Layer} this
     */
    setMask:function(mask) {
        if (!((mask instanceof Z.Marker && Z.symbolizer.VectorMarkerSymbolizer.test(mask, mask.getSymbol()))
            || mask instanceof Z.Polygon || mask instanceof Z.MultiPolygon)) {
            throw new Error('mask has to be a Marker with vector symbol, a Polygon or a MultiPolygon');
        }

        mask._bindLayer(this);
        mask._enableRenderImmediate();
        if (mask instanceof Z.Marker ) {
            mask.setSymbol(Z.Util.extendSymbol(mask.getSymbol(),{
                'markerLineWidth': 0,
                'markerFillOpacity': 0
            }));
        } else {
            mask.setSymbol({
                'lineWidth':0,
                'polygonOpacity':0
            });
        }
        this._mask = mask;
        if (!this.getMap() || this.getMap()._isBusy()) {
            return this;
        }
        var renderer = this._getRenderer();
        renderer && renderer.render();
        return this;
    },

    /**
     * Clear the mask
     * @returns {maptalks.Layer} this
     */
    clearMask:function() {
        delete this._mask;
        if (!this.getMap() || this.getMap()._isBusy()) {
            return this;
        }
        var renderer = this._getRenderer();
        renderer && renderer.render();
        return this;
    },

    /**
     * Prepare Layer's loading, this is a method intended to be overrided by subclasses.
     * @return {Boolean} true to continue, false to cease.
     * @protected
     */
    _prepareLoad:function() {
        return true;
    },

    _onRemove:function() {
        this.clear();
        if (this._renderer) {
            this._renderer.remove();
            delete this._renderer;
        }
        delete this.map;
    },

    _bindMap:function(map,zIndex) {
        if (!map) {return;}
        this.map = map;
        this.setZIndex(zIndex);
        this.fire('add');
    },

    _initRenderer:function() {
        var renderer = this.options['renderer'];
        var clazz = this.constructor.getRendererClass(renderer);
        this._renderer = new clazz(this);
        this._renderer.setZIndex(this.getZIndex());
    },

    _getRenderer:function() {
        return this._renderer;
    },

    _getLayerList:function() {
        if (!this.map) {return null;}
        return this.map._layers;
    }
});
<commit_msg>allow layer not have any renderer<commit_after>/**
 * @classdesc
 * Base class for all the layers, defines common methods that all the layer classes share.
 * @class
 * @category layer
 * @abstract
 * @extends maptalks.Class
 * @mixes maptalks.Eventable
 * @mixes maptalks.Renderable
 */
Z.Layer=Z.Class.extend(/** @lends maptalks.Layer.prototype */{

    includes: Z.Eventable,

    /**
     * @property {Object}  [options=null] - base options of layer.
     * @property {Number}  [options.minZoom=-1] - the minimum zoom to display the layer, set to -1 to unlimit it.
     * @property {Number}  [options.maxZoom=-1] - the maximum zoom to display the layer, set to -1 to unlimit it.
     * @property {Boolean} [options.visible=true] - whether to display the layer.
     * @property {Number}  [options.opacity=1] - opacity of the layer, from 0 to 1.
     * @property {String}  [options.renderer=canvas] - renderer type. Don't change it if you are not sure about it. About renderer, see [TODO]{@link tutorial.renderer}.
     */
    options:{
        //最大最小可视范围, null表示不受限制
        'minZoom':null,
        'maxZoom':null,
        //图层是否可见
        'visible':true,
        'opacity': 1,
        'renderer' : 'canvas'
    },

     /**
     * load the tile layer, can't be overrided by sub-classes
     */
    load:function(){
        if (!this.getMap()) {return this;}
        this._initRenderer();
        var zIndex = this.getZIndex();
        if (!Z.Util.isNil(zIndex) && this._renderer) {
            this._renderer.setZIndex(zIndex);
        }
        if (this._prepareLoad()) {
            this._renderer && this._renderer.render();
        }
        return this;
    },

    /**
     * Get the layer id
     * @returns {String|Number} id
     */
    getId:function() {
        return this._id;
    },

    /**
     * Set a new id to the layer
     * @param {String|Number} id - new layer id
     * @return {maptalks.Layer} this
     * @fires maptalks.Layer#idchange
     */
    setId:function(id) {
        //TODO 设置id可能造成map无法找到layer
        var old = this._id;
        this._id = id;
        /**
         * idchange event.
         *
         * @event maptalks.Layer#idchange
         * @type {Object}
         * @property {String} type - idchange
         * @property {maptalks.Layer} target    - the layer fires the event
         * @property {String|Number} old        - value of the old id
         * @property {String|Number} new        - value of the new id
         */
        this.fire('idchange', {'old':old, 'new':id});
        return this;
    },

    /**
     * Adds itself to a map.
     * @param {maptalks.Map} map - map added to
     * @return {maptalks.Layer} this
     */
    addTo:function(map) {
        map.addLayer(this);
        return this;
    },

    /**
     * Set a z-index to the layer
     * @param {Number} zIndex - layer's z-index
     * @return {maptalks.Layer} this
     */
    setZIndex:function(zIndex) {
        this._zIndex = zIndex;
        if (this.map) {
            var layerList = this._getLayerList();
            this.map._sortLayersByZIndex(layerList);
        }
        if (this._renderer) {
            this._renderer.setZIndex(zIndex);
        }
        return this;
    },

    /**
     * Get the layer's z-index
     * @return {Number}
     */
    getZIndex:function() {
        return this._zIndex;
    },

    /**
     * If the layer is rendered by HTML5 Canvas 2d.
     * @return {Boolean}
     * @protected
     */
    isCanvasRender:function() {
        var renderer = this._getRenderer();
        if (renderer) {
            return renderer.isCanvasRender();
        }
        return false;
    },

    /**
     * Get the map that the layer added to
     * @returns {maptalks.Map}
     */
    getMap:function() {
        if (this.map) {
            return this.map;
        }
        return null;
    },

    /**
     * Brings the layer to the top of all the layers
     * @returns {maptalks.Layer} this
     */
    bringToFront:function() {
        var layers = this._getLayerList();
        if (!layers) {
            return this;
        }
        var topLayer = layers[layers.length-1];
        if (layers.length === 1 || topLayer === this) {
            return this;
        }
        var max = topLayer.getZIndex();
        this.setZIndex(max+1);
        return this;
    },

    /**
     * Brings the layer under the bottom of all the layers
     * @returns {maptalks.Layer} this
     */
    bringToBack:function(){
        var layers = this._getLayerList();
        if (!layers) {
            return this;
        }
        var bottomLayer = layers[0];
        if (layers.length === 1 || bottomLayer === this) {
            return this;
        }
        var min = bottomLayer.getZIndex();
        this.setZIndex(min-1);
        return this;
    },

    /**
     * Show the layer
     * @returns {maptalks.Layer} this
     */
    show:function() {
        if (!this.options['visible']) {
            this.options['visible'] = true;
            if (this._getRenderer()) {
                this._getRenderer().show();
            }
        }
        this.fire('show');
        return this;
    },

    /**
     * Hide the layer
     * @returns {maptalks.Layer} this
     */
    hide:function() {
        if (this.options['visible']) {
            this.options['visible'] = false;
            if (this._getRenderer()) {
                this._getRenderer().hide();
            }
        }
        this.fire('hide');
        return this;
    },

    isLoaded:function() {
        if (!this._renderer) {
            return false;
        }
        return this._renderer.isLoaded();
    },

    /**
     * Whether the layer is visible now.
     * @return {Boolean}
     */
    isVisible:function() {
        if (Z.Util.isNumber(this.options['opacity']) && this.options['opacity'] <= 0) {
            return false;
        }
        var map = this.getMap();
        if (map) {
            var zoom = map.getZoom();
            if ((!Z.Util.isNil(this.options['maxZoom']) && this.options['maxZoom'] < zoom)
                    || (!Z.Util.isNil(this.options['minZoom']) && this.options['minZoom'] > zoom)) {
                return false;
            }
        }

        if (Z.Util.isNil(this.options['visible'])) {
            this.options['visible'] = true;
        }
        return this.options['visible'];
    },

    /**
     * Remove itself from the map added to.
     * @returns {maptalks.Layer} this
     */
    remove:function() {
        if (this.map) {
            this.map.removeLayer(this);
        }
        return this;
    },

    /**
     * Get the mask geometry of the layer
     * @return {maptalks.Geometry}
     */
    getMask:function() {
        return this._mask;
    },

    /**
     * Set a mask geometry on the layer, only the area in the mask will be displayed.
     * @param {maptalks.Geometry} mask - mask geometry, can only be a Marker with vector symbol, a Polygon or a MultiPolygon
     * @returns {maptalks.Layer} this
     */
    setMask:function(mask) {
        if (!((mask instanceof Z.Marker && Z.symbolizer.VectorMarkerSymbolizer.test(mask, mask.getSymbol()))
            || mask instanceof Z.Polygon || mask instanceof Z.MultiPolygon)) {
            throw new Error('mask has to be a Marker with vector symbol, a Polygon or a MultiPolygon');
        }

        mask._bindLayer(this);
        mask._enableRenderImmediate();
        if (mask instanceof Z.Marker ) {
            mask.setSymbol(Z.Util.extendSymbol(mask.getSymbol(),{
                'markerLineWidth': 0,
                'markerFillOpacity': 0
            }));
        } else {
            mask.setSymbol({
                'lineWidth':0,
                'polygonOpacity':0
            });
        }
        this._mask = mask;
        if (!this.getMap() || this.getMap()._isBusy()) {
            return this;
        }
        var renderer = this._getRenderer();
        renderer && renderer.render();
        return this;
    },

    /**
     * Clear the mask
     * @returns {maptalks.Layer} this
     */
    clearMask:function() {
        delete this._mask;
        if (!this.getMap() || this.getMap()._isBusy()) {
            return this;
        }
        var renderer = this._getRenderer();
        renderer && renderer.render();
        return this;
    },

    /**
     * Set a parent layer to handle all the events
     * @param {maptralks.Layer} layer - parent layer
     * @return {maptalks.Layer} this
     */
    setEventParent:function(layer) {
        if (!(layer instanceof Z.Layer)) {
            throw new Error('It needs to be a layer to setEventParent.');
        }
        this._eventParent = layer;
        return this;
    },

    /**
     * Fire an event, causing all handlers for that event name to run.
     *
     * @param  {String} eventType - an event type to fire
     * @param  {Object} param     - parameters for the listener function.
     * @return {maptalks.Layer} this
     * @override
     */
    fire:function() {
        if (this._eventParent) {
            return this._eventParent.fire.apply(this._eventParent, arguments);
        }
        return this._fire.apply(this, arguments);
    },

    /**
     * Prepare Layer's loading, this is a method intended to be overrided by subclasses.
     * @return {Boolean} true to continue, false to cease.
     * @protected
     */
    _prepareLoad:function() {
        return true;
    },

    _onRemove:function() {
        this.clear();
        if (this._renderer) {
            this._renderer.remove();
            delete this._renderer;
        }
        delete this.map;
    },

    _bindMap:function(map,zIndex) {
        if (!map) {return;}
        this.map = map;
        this.setZIndex(zIndex);
        this.fire('add');
    },

    _initRenderer:function() {
        var renderer = this.options['renderer'];
        if (!this.constructor.getRendererClass) {
            return;
        }
        var clazz = this.constructor.getRendererClass(renderer);
        if (!clazz) {
            return;
        }
        this._renderer = new clazz(this);
        this._renderer.setZIndex(this.getZIndex());
    },

    _getRenderer:function() {
        return this._renderer;
    },

    _getLayerList:function() {
        if (!this.map) {return null;}
        return this.map._layers;
    }
});
<|endoftext|>


<commit_before>FBL.ns(function() { with (FBL) {
// ************************************************************************************************

Firebug.Reps = {

    appendText: function(object, html)
    {
        html.push(escapeHTML(objectToString(object)));
    },

    appendNull: function(object, html)
    {
        html.push('', escapeHTML(objectToString(object)), '');
    },

    appendString: function(object, html)
    {
        html.push('"', escapeHTML(objectToString(object)),
            '"');
    },

    appendInteger: function(object, html)
    {
        html.push('', escapeHTML(objectToString(object)), '');
    },

    appendFloat: function(object, html)
    {
        html.push('', escapeHTML(objectToString(object)), '');
    },

    appendFunction: function(object, html)
    {
        var reName = /function ?(.*?)\(/;
        var m = reName.exec(objectToString(object));
        var name = m && m[1] ? m[1] : "function";
        html.push('', escapeHTML(name), '()');
    },

    appendObject: function(object, html)
    {
        try
        {
            if (object == undefined)
                this.appendNull("undefined", html);
            else if (object == null)
                this.appendNull("null", html);
            else if (typeof object == "string")
                this.appendString(object, html);
            else if (typeof object == "number")
                this.appendInteger(object, html);
            else if (typeof object == "boolean")
                this.appendInteger(object, html);
            else if (typeof object == "function")
                this.appendFunction(object, html);
            else if (object.nodeType == 1)
                this.appendSelector(object, html);
            else if (typeof object == "object")
            {
                if (typeof object.length != "undefined")
                    this.appendArray(object, html);
                else
                    this.appendObjectFormatted(object, html);
            }
            else
                this.appendText(object, html);
        }
        catch (exc)
        {
        }
    },

    appendObjectFormatted: function(object, html)
    {
        var text = objectToString(object);
        var reObject = /\[object (.*?)\]/;

        var m = reObject.exec(text);
        html.push('', m ? m[1] : text, '')
    },

    appendSelector: function(object, html)
    {
        var uid = object[cacheID];
        var uidString = uid ? [cacheID, '="', uid, '" id="', uid, '"'].join("") : "";

        html.push('');

        html.push('', escapeHTML(object.nodeName.toLowerCase()), '');
        if (object.id)
            html.push('#', escapeHTML(object.id), '');
        if (object.className)
            html.push('.', escapeHTML(object.className), '');

        html.push('');
    },

    appendNode: function(node, html)
    {
        if (node.nodeType == 1)
        {
            var uid = node[cacheID];
            var uidString = uid ? [cacheID, '="', uid, '" id="', uid, '"'].join("") : "";

            html.push(
                '
',
                '',
                '<', node.nodeName.toLowerCase(), '');

            for (var i = 0; i < node.attributes.length; ++i)
            {
                var attr = node.attributes[i];
                if (!attr.specified)
                    continue;

                html.push(' ', attr.nodeName.toLowerCase(),
                    '="', escapeHTML(attr.nodeValue),
                    '"')
            }

            if (node.firstChild)
            {
                html.push('>

');

                for (var child = node.firstChild; child; child = child.nextSibling)
                    this.appendNode(child, html);

                html.push('

</',
                    node.nodeName.toLowerCase(), '>
');
            }
            else
                html.push('/>
');
        }
        else if (node.nodeType == 3)
        {
            html.push('
', escapeHTML(node.nodeValue),
                '
');
        }
    },

    appendArray: function(object, html)
    {
        html.push('[ ');

        for (var i = 0, l = object.length, obj; i < l; ++i)
        {
            this.appendObject(object[i], html);

            if (i < l-1)
            html.push(', ');
        }

        html.push(' ]');
    }

};

/*
From firebug

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Reps

    registerRep: function()
    {
        reps.push.apply(reps, arguments);
    },

    setDefaultRep: function(rep)
    {
        defaultRep = rep;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Reps

    getRep: function(object)
    {
        var type = typeof(object);
        for (var i = 0; i < reps.length; ++i)
        {
            var rep = reps[i];
            try
            {
                if (rep.supportsObject(object, type))
                    return rep;
            }
            catch (exc)
            {
                if (FBTrace.dumpProperties)
                {
                    FBTrace.dumpProperties("firebug.getRep FAILS at i/reps.length: "+i+"/"+reps.length+" type:"+type+" exc:", exc);
                    FBTrace.dumpProperties("firebug.getRep reps[i]", reps[i]);
                    FBTrace.dumpStack("firebug.getRep");
                }
            }
        }

        return defaultRep;
    },

    getRepObject: function(node)
    {
        var target = null;
        for (var child = node; child; child = child.parentNode)
        {
            if (hasClass(child, "repTarget"))
                target = child;

            if (child.repObject)
            {
                if (!target && hasClass(child, "repIgnore"))
                    break;
                else
                    return child.repObject;
            }
        }
    },

    getRepNode: function(node)
    {
        for (var child = node; child; child = child.parentNode)
        {
            if (child.repObject)
                return child;
        }
    },

    getElementByRepObject: function(element, object)
    {
        for (var child = element.firstChild; child; child = child.nextSibling)
        {
            if (child.repObject == object)
                return child;
        }
    },
/**/

// ************************************************************************************************
}});<commit_msg>Don't show cache attribute in HTML tree.<commit_after>FBL.ns(function() { with (FBL) {
// ************************************************************************************************

Firebug.Reps = {

    appendText: function(object, html)
    {
        html.push(escapeHTML(objectToString(object)));
    },

    appendNull: function(object, html)
    {
        html.push('', escapeHTML(objectToString(object)), '');
    },

    appendString: function(object, html)
    {
        html.push('"', escapeHTML(objectToString(object)),
            '"');
    },

    appendInteger: function(object, html)
    {
        html.push('', escapeHTML(objectToString(object)), '');
    },

    appendFloat: function(object, html)
    {
        html.push('', escapeHTML(objectToString(object)), '');
    },

    appendFunction: function(object, html)
    {
        var reName = /function ?(.*?)\(/;
        var m = reName.exec(objectToString(object));
        var name = m && m[1] ? m[1] : "function";
        html.push('', escapeHTML(name), '()');
    },

    appendObject: function(object, html)
    {
        try
        {
            if (object == undefined)
                this.appendNull("undefined", html);
            else if (object == null)
                this.appendNull("null", html);
            else if (typeof object == "string")
                this.appendString(object, html);
            else if (typeof object == "number")
                this.appendInteger(object, html);
            else if (typeof object == "boolean")
                this.appendInteger(object, html);
            else if (typeof object == "function")
                this.appendFunction(object, html);
            else if (object.nodeType == 1)
                this.appendSelector(object, html);
            else if (typeof object == "object")
            {
                if (typeof object.length != "undefined")
                    this.appendArray(object, html);
                else
                    this.appendObjectFormatted(object, html);
            }
            else
                this.appendText(object, html);
        }
        catch (exc)
        {
        }
    },

    appendObjectFormatted: function(object, html)
    {
        var text = objectToString(object);
        var reObject = /\[object (.*?)\]/;

        var m = reObject.exec(text);
        html.push('', m ? m[1] : text, '')
    },

    appendSelector: function(object, html)
    {
        var uid = object[cacheID];
        var uidString = uid ? [cacheID, '="', uid, '" id="', uid, '"'].join("") : "";

        html.push('');

        html.push('', escapeHTML(object.nodeName.toLowerCase()), '');
        if (object.id)
            html.push('#', escapeHTML(object.id), '');
        if (object.className)
            html.push('.', escapeHTML(object.className), '');

        html.push('');
    },

    appendNode: function(node, html)
    {
        if (node.nodeType == 1)
        {
            var uid = node[cacheID];
            var uidString = uid ? [cacheID, '="', uid, '" id="', uid, '"'].join("") : "";

            html.push(
                '
',
                '',
                '<', node.nodeName.toLowerCase(), '');

            for (var i = 0; i < node.attributes.length; ++i)
            {
                var attr = node.attributes[i];
                if (!attr.specified || attr.nodeName == cacheID)
                    continue;

                html.push(' ', attr.nodeName.toLowerCase(),
                    '="', escapeHTML(attr.nodeValue),
                    '"')
            }

            if (node.firstChild)
            {
                html.push('>

');

                for (var child = node.firstChild; child; child = child.nextSibling)
                    this.appendNode(child, html);

                html.push('

</',
                    node.nodeName.toLowerCase(), '>
');
            }
            else
                html.push('/>
');
        }
        else if (node.nodeType == 3)
        {
            html.push('
', escapeHTML(node.nodeValue),
                '
');
        }
    },

    appendArray: function(object, html)
    {
        html.push('[ ');

        for (var i = 0, l = object.length, obj; i < l; ++i)
        {
            this.appendObject(object[i], html);

            if (i < l-1)
            html.push(', ');
        }

        html.push(' ]');
    }

};

/*
From firebug

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Reps

    registerRep: function()
    {
        reps.push.apply(reps, arguments);
    },

    setDefaultRep: function(rep)
    {
        defaultRep = rep;
    },

    // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    // Reps

    getRep: function(object)
    {
        var type = typeof(object);
        for (var i = 0; i < reps.length; ++i)
        {
            var rep = reps[i];
            try
            {
                if (rep.supportsObject(object, type))
                    return rep;
            }
            catch (exc)
            {
                if (FBTrace.dumpProperties)
                {
                    FBTrace.dumpProperties("firebug.getRep FAILS at i/reps.length: "+i+"/"+reps.length+" type:"+type+" exc:", exc);
                    FBTrace.dumpProperties("firebug.getRep reps[i]", reps[i]);
                    FBTrace.dumpStack("firebug.getRep");
                }
            }
        }

        return defaultRep;
    },

    getRepObject: function(node)
    {
        var target = null;
        for (var child = node; child; child = child.parentNode)
        {
            if (hasClass(child, "repTarget"))
                target = child;

            if (child.repObject)
            {
                if (!target && hasClass(child, "repIgnore"))
                    break;
                else
                    return child.repObject;
            }
        }
    },

    getRepNode: function(node)
    {
        for (var child = node; child; child = child.parentNode)
        {
            if (child.repObject)
                return child;
        }
    },

    getElementByRepObject: function(element, object)
    {
        for (var child = element.firstChild; child; child = child.nextSibling)
        {
            if (child.repObject == object)
                return child;
        }
    },
/**/

// ************************************************************************************************
}});<|endoftext|>


<commit_before>var Leap = require('leapjs'),
    transform = require('../lib/leap.transform.js');

Leap.Controller.plugin('transform', transform);
Leap.plugin('aframeSystem', function(options) {
  options = options || {};
  this.use('transform', {vr: true});
  return {hand: function () {}};
});

/**
 * Leap Motion system for A-Frame.
 */
module.exports = {
  init: function () {
    this.controller = Leap.loop()
      .setOptimizeHMD(true)
      .use('aframeSystem');
  },

  getFrame: function () {
    return this.controller.frame();
  }
};
<commit_msg>Add transform options to leap system. (#14)<commit_after>var Leap = require('leapjs'),
    transform = require('../lib/leap.transform.js');

// Defaults from leap.transform.js.
var DEFAULT_SCALE = 0.001;
var DEFAULT_POSITION = new THREE.Vector3();
var DEFAULT_QUATERNION = new THREE.Quaternion();

Leap.Controller.plugin('transform', transform);

/**
 * Leap Motion system for A-Frame.
 */
module.exports = {
  schema: {
    vr: {default: true},
    scale: {default: DEFAULT_SCALE},
    position: {
      type: 'vec3',
      default: {
        x: DEFAULT_POSITION.x,
        y: DEFAULT_POSITION.y,
        z: DEFAULT_POSITION.z,
      }
    },
    quaternion: {
      type: 'vec4',
      default: {
        x: DEFAULT_QUATERNION.x,
        y: DEFAULT_QUATERNION.y,
        z: DEFAULT_QUATERNION.z,
        w: DEFAULT_QUATERNION.w
      }
    }
  },

  init: function () {
    this.controller = Leap.loop()
      .use('transform', this.data);
  },

  getFrame: function () {
    return this.controller.frame();
  }
};
<|endoftext|>


<commit_before>var Promise = require('bluebird')
var request = Promise.promisifyAll(require("request"))
var iconv = require("iconv-lite")
var cheerio = require("cheerio")
var urlencode = require('urlencode')
var redis = require('../Service/Redis.js');

var j = request.jar()

var get = function (ggdb, account, password) {
    return new Promise(function (resolve, reject) {
        var login = {
            url: "http://www.mcu.edu.tw/student/new-query/Chk_Pass_New_v1.asp",
            jar: j,
            form: {
                "t_tea_no": account,
                "t_tea_pass": password
            },
            encoding: "binary"
            //followAllRedirects: true
        }
        request.postAsync(login).then(function (res) {
            var cookies = j.getCookieString("http://www.mcu.edu.tw/student/new-query/Chk_Pass_New_v1.asp");
            if(cookies.split(";").filter((value)=>{return value.search("std%5Fno")!=-1})[0].search("error")!=-1) reject("帳號密碼錯誤")
            var result = {
                url: "http://www.mcu.edu.tw/student/new-query/sel-5-2.asp?d=5",
                jar: j,
                encoding: "binary",
                followAllRedirects: true
            }
            return request.getAsync(result);
        }).then(function (res) {
            //console.log(res.body);
            let $ = cheerio.load(iconv.decode(new Buffer(res.body, "binary"), "Big5"))
            return listParser($, ggdb)
        }).then(function (result) {
            resolve(result)
        }).catch(function (error) {
            reject(error)
        })
    })
}

var listParser = function ($, ggdb) {
    return new Promise(function (resolve, reject) {
        var rows = $("table").eq(1).children("tr");
        var list = [];
        for (var i = 2; i < rows.length; i += 2) {
            var sub = rows.eq(i).children();
            var subjectId = sub.eq(1).text().trim().split("　")[0];
            var classId = sub.eq(0).text().trim();
            list.push({
                subjectId: subjectId,
                classId: classId
            });
        }
        var cookie = request.cookie('ggdb='+ggdb);
        var url = 'http://www.mcu.edu.tw/student/new-query/sel-query/';
        j.setCookie(cookie, url);
        Promise.map(list, function (list) {
            return fetchCourse(ggdb, list.subjectId, list.classId)
        }, {
            concurrency: 5
        }).then(function (courses) {
            resolve(courses)
        }).catch(function (error) {
            reject(error)
        })

    })
}

var fetchCourse = function (ggdb, subjectId, classId) {
    return new Promise(function (resolve, reject) {
        redis.exists("course:"+ggdb+":subject:" + subjectId).then(function (value) {
            if (value == 1) {
                redis.get("course:"+ggdb+":subject:" + subjectId).then(function (result) {
                    let $ = cheerio.load(iconv.decode(new Buffer(result, "binary"), "Big5"));
                    resolve(fetchParser($, classId))
                }).catch(function (error) {
                    reject(error);
                })
            } else {
                var formData = "sch=&dept1=&yr1=&dept2=&yr2=&dept3=&yr3=&sel=&courna="+urlencode(subjectId,"Big5")+"&teana=&wk1=&ssec1=&esec1=&wk2=&ssec2=&esec2=&wk3=&ssec3=&esec3=&wk4=&ssec4=&esec4=";
                var contentLength = formData.length;

                var result = {
                    url: "http://www.mcu.edu.tw/student/new-query/sel-query/qslist_1.asp",
                    headers: {
                        'Content-Length': contentLength,
                        'Content-Type': 'application/x-www-form-urlencoded'
                    },
                    body: formData,
                    jar: j,
                    encoding: "binary",
                    followAllRedirects: true
                }
                request.postAsync(result).then(function (res) {
                    redis.set("course:"+ggdb+":subject:" + subjectId,res.body).then(function(){
                        redis.expire("course:"+ggdb+":subject:" + subjectId,3600).then();
                    })
                    let $ = cheerio.load(iconv.decode(new Buffer(res.body, "binary"), "Big5"));
                    resolve(fetchParser($, classId))
                }).catch(function (error) {
                    reject(error);
                })
            }
        }).catch(function (error) {
            reject(error);
        })
    })
}

var fetchParser = function ($, classId) {
    var rows = $("table tr");
    for (var i = 1; i < rows.length; i++) {
        var sub = rows.eq(i).children();
        if (sub.eq(2).text().trim().split(' ')[0].trim() == classId) {
            var course = {
                depart: sub.eq(0).text().trim(),
                subjectId: sub.eq(1).text().trim().split(' ')[0].trim(),
                subjectName: sub.eq(1).text().trim().split(' ')[1].trim(),
                classId: sub.eq(2).text().trim().split(' ')[0],
                className: sub.eq(2).text().trim().split(' ')[1],
                maxPeople: parseInt(sub.eq(3).text().trim().split('／')[0].trim()),
                nowPeople: parseInt(sub.eq(3).text().trim().split('／')[1].trim()),
                teacher: sub.eq(4).find("font").contents().map(function () {
                    return (this.type === 'text') ? $(this).text() : ''
                }).get().filter((value) => {
                    return value.length > 0
                }),
                time: formatTime(sub.eq(5).has("font").contents()[0].children),
                site: sub.eq(7).text().trim(),
                type: sub.eq(8).text().trim(),
                credit: parseInt(sub.eq(9).text()),
                note: (sub.eq(10).text() + " " + sub.eq(13).text()).trim()
            };
            if (sub.eq(4).find("a").length > 0) {
                course.detail = sub.eq(4).find("a").attr("href");
            }
            return course;
        }
    }
}

var formatTime = function (data) {
    //console.log(data)
    var temp = [];
    data.map(function (ele) {
        if (ele.type === 'text') {
            temp.push(ele.data);
        }
    });
    var result = [];
    temp.map(function (ele) {
        if (ele.match(":") != null) {
            //console.log(ele.split(":")[0].trim())
            var sub = {
                day: parseInt(ele.split(":")[0].trim().split(" ")[1]),
                sec: []
            }
            ele.split(":")[1].trim().split(" ").map(function (element) {
                if (!isNaN(parseInt(element))) {
                    sub.sec.push(parseInt(element));
                }
            });
            result.push(sub);
        }
    })
    return result;
}

module.exports = {
    get: get
}<commit_msg>fix my course api<commit_after>var Promise = require('bluebird')
var request = Promise.promisifyAll(require("request"))
var iconv = require("iconv-lite")
var cheerio = require("cheerio")
var urlencode = require('urlencode')
var redis = require('../Service/Redis.js');

var j = request.jar()

var get = function (ggdb, account, password) {
    return new Promise(function (resolve, reject) {
        var login = {
            url: "http://www.mcu.edu.tw/student/new-query/Chk_Pass_New_v1.asp",
            jar: j,
            form: {
                "t_tea_no": account,
                "t_tea_pass": password
            },
            encoding: "binary"
            //followAllRedirects: true
        }
        request.postAsync(login).then(function (res) {
            var cookies = j.getCookieString("http://www.mcu.edu.tw/student/new-query/Chk_Pass_New_v1.asp");
            if(cookies.split(";").filter((value)=>{return value.search("std%5Fno")!=-1})[0].search("error")!=-1) reject("帳號密碼錯誤")
            var result = {
                url: "http://www.mcu.edu.tw/student/new-query/sel-5-2.asp?d=5",
                jar: j,
                encoding: "binary",
                followAllRedirects: true
            }
            return request.getAsync(result);
        }).then(function (res) {
            //console.log(iconv.decode(new Buffer(res.body, "binary"), "Big5"));
            let $ = cheerio.load(iconv.decode(new Buffer(res.body, "binary"), "Big5"))
            return listParser($, ggdb)
        }).then(function (result) {
            resolve(result)
        }).catch(function (error) {
            reject(error)
        })
    })
}

var listParser = function ($, ggdb) {
    return new Promise(function (resolve, reject) {
        var rows = $("table").eq(1).children("tr");
        //console.log(rows.eq(3).text())
        var list = [];
        for (var i = 2; i < rows.length; i++) {
            var sub = rows.eq(i).find("td");
            //console.log(sub.html());
            var subjectId = sub.eq(1).text().trim().split("　")[0];
            var classId = sub.eq(0).text().trim();
            list.push({
                subjectId: subjectId,
                classId: classId
            });
        }
        //console.log(list);
        var cookie = request.cookie('ggdb='+ggdb);
        var url = 'http://www.mcu.edu.tw/student/new-query/sel-query/';
        j.setCookie(cookie, url);
        Promise.map(list, function (list) {
            return fetchCourse(ggdb, list.subjectId, list.classId)
        }, {
            concurrency: 5
        }).then(function (courses) {
            resolve(courses)
        }).catch(function (error) {
            reject(error)
        })

    })
}

var fetchCourse = function (ggdb, subjectId, classId) {
    return new Promise(function (resolve, reject) {
        redis.exists("course:"+ggdb+":subject:" + subjectId).then(function (value) {
            if (value == 1) {
                redis.get("course:"+ggdb+":subject:" + subjectId).then(function (result) {
                    let $ = cheerio.load(iconv.decode(new Buffer(result, "binary"), "Big5"));
                    resolve(fetchParser($, classId))
                }).catch(function (error) {
                    reject(error);
                })
            } else {
                var formData = "sch=&dept1=&yr1=&dept2=&yr2=&dept3=&yr3=&sel=&courna="+urlencode(subjectId,"Big5")+"&teana=&wk1=&ssec1=&esec1=&wk2=&ssec2=&esec2=&wk3=&ssec3=&esec3=&wk4=&ssec4=&esec4=";
                var contentLength = formData.length;

                var result = {
                    url: "http://www.mcu.edu.tw/student/new-query/sel-query/qslist_1.asp",
                    headers: {
                        'Content-Length': contentLength,
                        'Content-Type': 'application/x-www-form-urlencoded'
                    },
                    body: formData,
                    jar: j,
                    encoding: "binary",
                    followAllRedirects: true
                }
                request.postAsync(result).then(function (res) {
                    redis.set("course:"+ggdb+":subject:" + subjectId,res.body).then(function(){
                        redis.expire("course:"+ggdb+":subject:" + subjectId,3600).then();
                    })
                    let $ = cheerio.load(iconv.decode(new Buffer(res.body, "binary"), "Big5"));
                    resolve(fetchParser($, classId))
                }).catch(function (error) {
                    reject(error);
                })
            }
        }).catch(function (error) {
            reject(error);
        })
    })
}

var fetchParser = function ($, classId) {
    var rows = $("table tr");
    for (var i = 1; i < rows.length; i++) {
        var sub = rows.eq(i).children();
        if (sub.eq(2).text().trim().split(' ')[0].trim() == classId) {
            var course = {
                depart: sub.eq(0).text().trim(),
                subjectId: sub.eq(1).text().trim().split(' ')[0].trim(),
                subjectName: sub.eq(1).text().trim().split(' ')[1].trim(),
                classId: sub.eq(2).text().trim().split(' ')[0],
                className: sub.eq(2).text().trim().split(' ')[1],
                maxPeople: parseInt(sub.eq(3).text().trim().split('／')[0].trim()),
                nowPeople: parseInt(sub.eq(3).text().trim().split('／')[1].trim()),
                teacher: sub.eq(4).find("font").contents().map(function () {
                    return (this.type === 'text') ? $(this).text() : ''
                }).get().filter((value) => {
                    return value.length > 0
                }),
                time: formatTime(sub.eq(5).has("font").contents()[0].children),
                site: sub.eq(7).text().trim(),
                type: sub.eq(8).text().trim(),
                credit: parseInt(sub.eq(9).text()),
                note: (sub.eq(10).text() + " " + sub.eq(13).text()).trim()
            };
            if (sub.eq(4).find("a").length > 0) {
                course.detail = sub.eq(4).find("a").attr("href");
            }
            return course;
        }
    }
}

var formatTime = function (data) {
    //console.log(data)
    var temp = [];
    data.map(function (ele) {
        if (ele.type === 'text') {
            temp.push(ele.data);
        }
    });
    var result = [];
    temp.map(function (ele) {
        if (ele.match(":") != null) {
            //console.log(ele.split(":")[0].trim())
            var sub = {
                day: parseInt(ele.split(":")[0].trim().split(" ")[1]),
                sec: []
            }
            ele.split(":")[1].trim().split(" ").map(function (element) {
                if (!isNaN(parseInt(element))) {
                    sub.sec.push(parseInt(element));
                }
            });
            result.push(sub);
        }
    })
    return result;
}

module.exports = {
    get: get
}<|endoftext|>


<commit_before>var Promise = require('bluebird')
var request = Promise.promisifyAll(require("request"))
var iconv = require("iconv-lite")
var cheerio = require("cheerio")
var urlencode = require('urlencode')
var redis = require('../Service/Redis.js');

var j = request.jar()

var get = function (ggdb, account, password) {
    return new Promise(function (resolve, reject) {
        var login = {
            url: "http://www.mcu.edu.tw/student/new-query/Chk_Pass_New_v1.asp",
            jar: j,
            form: {
                "t_tea_no": account,
                "t_tea_pass": password
            },
            encoding: "binary"
            //followAllRedirects: true
        }
        request.postAsync(login).then(function (res) {
            var cookies = j.getCookieString("http://www.mcu.edu.tw/student/new-query/Chk_Pass_New_v1.asp");
            if (cookies.split(";").filter((value) => { return value.search("std%5Fno") != -1 })[0].search("error") != -1) reject("帳號密碼錯誤")
            var result = {
                url: "http://www.mcu.edu.tw/student/new-query/sel-5-2.asp?d=5",
                jar: j,
                encoding: "binary",
                followAllRedirects: true
            }
            return request.getAsync(result);
        }).then(function (res) {
            //console.log(iconv.decode(new Buffer(res.body, "binary"), "Big5"));
            let $ = cheerio.load(iconv.decode(new Buffer(res.body, "binary"), "Big5"))
            return listParser($, ggdb)
        }).then(function (result) {
            resolve(result)
        }).catch(function (error) {
            reject(error)
        })
    })
}

var listParser = function ($, ggdb) {
    return new Promise(function (resolve, reject) {
        var rows = $("table").eq(1).children("tr");
        //console.log(rows.eq(3).text())
        var list = [];
        for (var i = 2; i < rows.length; i++) {
            var sub = rows.eq(i).find("td");
            //console.log(sub.html());
            var subjectId = sub.eq(1).text().trim().split("　")[0];
            var classId = sub.eq(0).text().trim();
            list.push({
                subjectId: subjectId,
                classId: classId
            });
        }
        //console.log(list);
        var cookie = request.cookie('ggdb=' + ggdb);
        var url = 'http://www.mcu.edu.tw/student/new-query/sel-query/';
        j.setCookie(cookie, url);
        Promise.map(list, function (list) {
            return fetchCourse(ggdb, list.subjectId, list.classId)
        }, {
                concurrency: 5
            }).then(function (courses) {
                resolve(courses)
            }).catch(function (error) {
                reject(error)
            })

    })
}

var fetchCourse = function (ggdb, subjectId, classId) {
    return new Promise(function (resolve, reject) {
        redis.exists("course:" + ggdb + ":subject:" + subjectId).then(function (value) {
            if (value == 1) {
                redis.get("course:" + ggdb + ":subject:" + subjectId).then(function (result) {
                    let $ = cheerio.load(iconv.decode(new Buffer(result, "binary"), "Big5"));
                    resolve(fetchParser($, classId))
                }).catch(function (error) {
                    reject(error);
                })
            } else {
                var formData = "sch=&dept1=&yr1=&dept2=&yr2=&dept3=&yr3=&sel=&courna=" + urlencode(subjectId, "Big5") + "&teana=&wk1=&ssec1=&esec1=&wk2=&ssec2=&esec2=&wk3=&ssec3=&esec3=&wk4=&ssec4=&esec4=";
                var contentLength = formData.length;

                var result = {
                    url: "http://www.mcu.edu.tw/student/new-query/sel-query/qslist_1.asp",
                    headers: {
                        'Content-Length': contentLength,
                        'Content-Type': 'application/x-www-form-urlencoded'
                    },
                    body: formData,
                    jar: j,
                    encoding: "binary",
                    followAllRedirects: true
                }
                request.postAsync(result).then(function (res) {
                    redis.set("course:" + ggdb + ":subject:" + subjectId, res.body).then(function () {
                        redis.expire("course:" + ggdb + ":subject:" + subjectId, 3600).then();
                    })
                    let $ = cheerio.load(iconv.decode(new Buffer(res.body, "binary"), "Big5"));
                    resolve(fetchParser($, classId))
                }).catch(function (error) {
                    reject(error);
                })
            }
        }).catch(function (error) {
            reject(error);
        })
    })
}

var fetchParser = function ($, classId) {
    var rows = $("table tr");
    for (var i = 1; i < rows.length; i++) {
        var sub = rows.eq(i).children();
        if (sub.eq(2).text().trim().split(' ')[0].trim() == classId) {
            var course = {
                depart: sub.eq(0).text().trim(),
                subjectId: sub.eq(1).text().trim().split(' ')[0].trim(),
                subjectName: sub.eq(1).text().trim().split(' ').slice(1, sub.eq(1).text().trim().split(' ').length + 1).join(' '),
                classId: sub.eq(2).text().trim().split(' ')[0],
                className: sub.eq(2).text().trim().split(' ')[1],
                maxPeople: parseInt(sub.eq(3).text().trim().split('／')[0].trim()),
                nowPeople: parseInt(sub.eq(3).text().trim().split('／')[1].trim()),
                teacher: sub.eq(4).find("font").contents().map(function () {
                    return (this.type === 'text') ? $(this).text().substring(4) : ''
                }).get().filter((value) => {
                    return value.length > 0
                }),
                time: formatTime(sub.eq(5).has("font").contents()[0].children),
                site: sub.eq(7).find("font").contents().map(function () {
                    return (this.type === 'text') ? $(this).text() : ''
                }).get().filter((value) => {
                    return value.length > 0
                }).map((element) => {
                    return element.substring(0, (element.indexOf("【") != -1) ? element.indexOf("【") : element.length + 1)
                }),
                type: sub.eq(8).text().trim(),
                credit: parseInt(sub.eq(9).text()),
                note: (sub.eq(10).text() + " " + sub.eq(13).text()).trim()
            };
            if (sub.eq(4).find("a").length > 0) {
                course.detail = sub.eq(4).find("a").attr("href").replace("學年度", "105");
            }
            return course;
        }
    }
}

var formatTime = function (data) {
    //console.log(data)
    var temp = [];
    data.map(function (ele) {
        if (ele.type === 'text') {
            temp.push(ele.data);
        }
    });
    var result = [];
    temp.map(function (ele) {
        if (ele.match(":") != null) {
            //console.log(ele.split(":")[0].trim())
            var sub = {
                day: parseInt(ele.split(":")[0].trim().split(" ")[1]),
                sec: []
            }
            ele.split(":")[1].trim().split(" ").map(function (element) {
                if (!isNaN(parseInt(element))) {
                    sub.sec.push(parseInt(element));
                }
            });
            result.push(sub);
        }
    })
    return result;
}

module.exports = {
    get: get
}<commit_msg>fix repeat my courses<commit_after>var Promise = require('bluebird')
var request = Promise.promisifyAll(require("request"))
var iconv = require("iconv-lite")
var cheerio = require("cheerio")
var urlencode = require('urlencode')
var redis = require('../Service/Redis.js');

var j = request.jar()

var get = function (ggdb, account, password) {
    return new Promise(function (resolve, reject) {
        var login = {
            url: "http://www.mcu.edu.tw/student/new-query/Chk_Pass_New_v1.asp",
            jar: j,
            form: {
                "t_tea_no": account,
                "t_tea_pass": password
            },
            encoding: "binary"
            //followAllRedirects: true
        }
        request.postAsync(login).then(function (res) {
            var cookies = j.getCookieString("http://www.mcu.edu.tw/student/new-query/Chk_Pass_New_v1.asp");
            if (cookies.split(";").filter((value) => { return value.search("std%5Fno") != -1 })[0].search("error") != -1) reject("帳號密碼錯誤")
            var result = {
                url: "http://www.mcu.edu.tw/student/new-query/sel-5-2.asp?d=5",
                jar: j,
                encoding: "binary",
                followAllRedirects: true
            }
            return request.getAsync(result);
        }).then(function (res) {
            //console.log(iconv.decode(new Buffer(res.body, "binary"), "Big5"));
            let $ = cheerio.load(iconv.decode(new Buffer(res.body, "binary"), "Big5"))
            return listParser($, ggdb)
        }).then(function (result) {
            resolve(result)
        }).catch(function (error) {
            reject(error)
        })
    })
}

var listParser = function ($, ggdb) {
    return new Promise(function (resolve, reject) {
        var rows = $("table").eq(1).children("tr");
        //console.log(rows.eq(3).text())
        var list = [];
        for (var i = 2; i < rows.length; i++) {
            var sub = rows.eq(i).find("td");
            //console.log(sub.html());
            var subjectId = sub.eq(1).text().trim().split("　")[0];
            var classId = sub.eq(0).text().trim();
            if(list.filter((element)=>{ return ((element.classId==classId)&&(element.subjectId==subjectId)) }).length==0){
                list.push({
                    subjectId: subjectId,
                    classId: classId
                });
            }

        }
        //console.log(list);
        var cookie = request.cookie('ggdb=' + ggdb);
        var url = 'http://www.mcu.edu.tw/student/new-query/sel-query/';
        j.setCookie(cookie, url);
        Promise.map(list, function (list) {
            return fetchCourse(ggdb, list.subjectId, list.classId)
        }, {
            concurrency: 5
        }).then(function (courses) {
            resolve(courses)
        }).catch(function (error) {
            reject(error)
        })

    })
}

var fetchCourse = function (ggdb, subjectId, classId) {
    return new Promise(function (resolve, reject) {
        redis.exists("course:" + ggdb + ":subject:" + subjectId).then(function (value) {
            if (value == 1) {
                redis.get("course:" + ggdb + ":subject:" + subjectId).then(function (result) {
                    let $ = cheerio.load(iconv.decode(new Buffer(result, "binary"), "Big5"));
                    resolve(fetchParser($, classId))
                }).catch(function (error) {
                    reject(error);
                })
            } else {
                var formData = "sch=&dept1=&yr1=&dept2=&yr2=&dept3=&yr3=&sel=&courna=" + urlencode(subjectId, "Big5") + "&teana=&wk1=&ssec1=&esec1=&wk2=&ssec2=&esec2=&wk3=&ssec3=&esec3=&wk4=&ssec4=&esec4=";
                var contentLength = formData.length;

                var result = {
                    url: "http://www.mcu.edu.tw/student/new-query/sel-query/qslist_1.asp",
                    headers: {
                        'Content-Length': contentLength,
                        'Content-Type': 'application/x-www-form-urlencoded'
                    },
                    body: formData,
                    jar: j,
                    encoding: "binary",
                    followAllRedirects: true
                }
                request.postAsync(result).then(function (res) {
                    redis.set("course:" + ggdb + ":subject:" + subjectId, res.body).then(function () {
                        redis.expire("course:" + ggdb + ":subject:" + subjectId, 3600).then();
                    })
                    let $ = cheerio.load(iconv.decode(new Buffer(res.body, "binary"), "Big5"));
                    resolve(fetchParser($, classId))
                }).catch(function (error) {
                    reject(error);
                })
            }
        }).catch(function (error) {
            reject(error);
        })
    })
}

var fetchParser = function ($, classId) {
    var rows = $("table tr");
    for (var i = 1; i < rows.length; i++) {
        var sub = rows.eq(i).children();
        if (sub.eq(2).text().trim().split(' ')[0].trim() == classId) {
            var course = {
                depart: sub.eq(0).text().trim(),
                subjectId: sub.eq(1).text().trim().split(' ')[0].trim(),
                subjectName: sub.eq(1).text().trim().split(' ').slice(1, sub.eq(1).text().trim().split(' ').length + 1).join(' '),
                classId: sub.eq(2).text().trim().split(' ')[0],
                className: sub.eq(2).text().trim().split(' ')[1],
                maxPeople: parseInt(sub.eq(3).text().trim().split('／')[0].trim()),
                nowPeople: parseInt(sub.eq(3).text().trim().split('／')[1].trim()),
                teacher: sub.eq(4).find("font").contents().map(function () {
                    return (this.type === 'text') ? $(this).text().substring(4) : ''
                }).get().filter((value) => {
                    return value.length > 0
                }),
                time: formatTime(sub.eq(5).has("font").contents()[0].children),
                site: sub.eq(7).find("font").contents().map(function () {
                    return (this.type === 'text') ? $(this).text() : ''
                }).get().filter((value) => {
                    return value.length > 0
                }).map((element) => {
                    return element.substring(0, (element.indexOf("【") != -1) ? element.indexOf("【") : element.length + 1)
                }),
                type: sub.eq(8).text().trim(),
                credit: parseInt(sub.eq(9).text()),
                note: (sub.eq(10).text() + " " + sub.eq(13).text()).trim()
            };
            if (sub.eq(4).find("a").length > 0) {
                course.detail = sub.eq(4).find("a").attr("href").replace("學年度", "105");
            }
            return course;
        }
    }
}

var formatTime = function (data) {
    //console.log(data)
    var temp = [];
    data.map(function (ele) {
        if (ele.type === 'text') {
            temp.push(ele.data);
        }
    });
    var result = [];
    temp.map(function (ele) {
        if (ele.match(":") != null) {
            //console.log(ele.split(":")[0].trim())
            var sub = {
                day: parseInt(ele.split(":")[0].trim().split(" ")[1]),
                sec: []
            }
            ele.split(":")[1].trim().split(" ").map(function (element) {
                if (!isNaN(parseInt(element))) {
                    sub.sec.push(parseInt(element));
                }
            });
            result.push(sub);
        }
    })
    return result;
}

module.exports = {
    get: get
}<|endoftext|>