<commit_before>
'use strict';
var Encounter = require('./encounter');
var Pirates = require('./pirates');

var treasureResults = new Array(9);

/**
 * The treasure encounter is a good encounter
 *
 * @constructor
 */
function Treasure() {
  this.effectResults = treasureResults;
  this.titleText = 'Treasure';
  this.soundText = 'treasurefx';
}

var t1 = {
  flavorText: 'Found a shipwreck',
  frame: 9,
  outcomes: [
    {
      flavorText: 'Dive for their treasure maps',
      mechanicsText: '-1 stamina, add 1 treasure',
      effectFunc: function(ship, encounterManager) {
        ship.stamina -= 1;
        encounterManager.add(Treasure);
      }
    },
    {
      flavorText: 'Leave it',
      mechanicsText: 'nothing',
      effectFunc: function(ship, encounterManager) {
        // Do nothing
      }
    },
  ]
};

var t2 = {
  flavorText: 'Buried Treasure!',
  frame: 3,
  outcomes: [
    {
      flavorText: 'Dig it up',
      mechanicsText: '+1 gold, remove 1 treasure',
      effectFunc: function(ship, encounterManager) {
        ship.treasure += 1;
        encounterManager.remove(Treasure);
      }
    },
  ]
};

var t3 = {
  flavorText: 'Lost Ancient Treasure!',
  frame: 4,
  outcomes: [
    {
      flavorText: 'Use it',
      mechanicsText: '+3 stamina',
      effectFunc: function(ship, encounterManager) {
        ship.stamina += 3;
      }
    },
    {
      flavorText: 'Sell it',
      mechanicsText: '+1 gold, add 1 pirate',
      effectFunc: function(ship, encounterManager) {
        ship.treasure += 1;
        encounterManager.remove(Treasure);
        encounterManager.add(Pirates);
      }
    },
  ]
};

var t4 = {
  flavorText: 'False lead...',
  frame: 5,
  outcomes: [
    {
      flavorText: 'Arr',
      mechanicsText: 'remove 1 treasure',
      effectFunc: function(ship, encounterManager) {
        encounterManager.remove(Treasure);
      }
    }
  ]
};

treasureResults[1] = t1;
treasureResults[2] = t1;
treasureResults[3] = t2;
treasureResults[4] = t2;
treasureResults[5] = t2;
treasureResults[6] = t3;
treasureResults[7] = t3;
treasureResults[8] = t4;

Treasure.prototype = new Encounter();
Treasure.prototype.constructor = Treasure;

module.exports = Treasure;
<commit_msg>Derp Encounter<commit_after>
'use strict';
var Encounter = require('./encounter');
var Pirates = require('./pirates');

var treasureResults = new Array(9);

/**
 * The treasure encounter is a good encounter
 *
 * @constructor
 */
function Treasure() {
  this.effectResults = treasureResults;
  this.titleText = 'Treasure';
  this.soundText = 'treasurefx';
}

var t1 = {
  flavorText: 'Found a shipwreck',
  frame: 9,
  outcomes: [
    {
      flavorText: 'Dive for their treasure maps',
      mechanicsText: '-1 stamina, add 1 treasure',
      effectFunc: function(ship, encounterManager) {
        ship.stamina -= 1;
        encounterManager.add(Treasure);
      }
    },
    {
      flavorText: 'Leave it',
      mechanicsText: 'nothing',
      effectFunc: function(ship, encounterManager) {
        // Do nothing
      }
    },
  ]
};

var t2 = {
  flavorText: 'Buried Treasure!',
  frame: 3,
  outcomes: [
    {
      flavorText: 'Dig it up',
      mechanicsText: '+1 gold, remove 1 treasure',
      effectFunc: function(ship, encounterManager) {
        ship.treasure += 1;
        encounterManager.remove(Treasure);
      }
    },
  ]
};

var t3 = {
  flavorText: 'Lost Ancient Treasure!',
  frame: 4,
  outcomes: [
    {
      flavorText: 'Use it',
      mechanicsText: '+3 stamina',
      effectFunc: function(ship, encounterManager) {
        ship.stamina += 3;
      }
    },
    {
      flavorText: 'Sell it',
      mechanicsText: '+1 gold, add 1 pirate',
      effectFunc: function(ship, encounterManager) {
        ship.treasure += 1;
        encounterManager.add(Pirates);
      }
    },
  ]
};

var t4 = {
  flavorText: 'False lead...',
  frame: 5,
  outcomes: [
    {
      flavorText: 'Arr',
      mechanicsText: 'remove 1 treasure',
      effectFunc: function(ship, encounterManager) {
        encounterManager.remove(Treasure);
      }
    }
  ]
};

treasureResults[1] = t1;
treasureResults[2] = t1;
treasureResults[3] = t2;
treasureResults[4] = t2;
treasureResults[5] = t2;
treasureResults[6] = t3;
treasureResults[7] = t3;
treasureResults[8] = t4;

Treasure.prototype = new Encounter();
Treasure.prototype.constructor = Treasure;

module.exports = Treasure;
<|endoftext|>


<commit_before>(function($) {
  $.extend($.summernote.lang, {
    'bg-BG': {
      font: {
        bold: 'Удебелен',
        italic: 'Наклонен',
        underline: 'Подчертан',
        clear: 'Изчисти стиловете',
        height: 'Височина',
        name: 'Шрифт',
        strikethrough: 'Задраскано',
        subscript: 'Долен индекс',
        superscript: 'Горен индекс',
        size: 'Размер на шрифта',
      },
      image: {
        image: 'Изображение',
        insert: 'Постави картинка',
        resizeFull: 'Цял размер',
        resizeHalf: 'Размер на 50%',
        resizeQuarter: 'Размер на 25%',
        floatLeft: 'Подравни в ляво',
        floatRight: 'Подравни в дясно',
        floatNone: 'Без подравняване',
        shapeRounded: 'Shape: Rounded',
        shapeCircle: 'Shape: Circle',
        shapeThumbnail: 'Shape: Thumbnail',
        shapeNone: 'Shape: None',
        dragImageHere: 'Пуснете изображението тук',
        dropImage: 'Drop image or Text',
        selectFromFiles: 'Изберете файл',
        maximumFileSize: 'Maximum file size',
        maximumFileSizeError: 'Maximum file size exceeded.',
        url: 'URL адрес на изображение',
        remove: 'Премахни изображение',
        original: 'Original',
      },
      video: {
        video: 'Video',
        videoLink: 'Video Link',
        insert: 'Insert Video',
        url: 'Video URL?',
        providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion or Youku)',
      },
      link: {
        link: 'Връзка',
        insert: 'Добави връзка',
        unlink: 'Премахни връзка',
        edit: 'Промени',
        textToDisplay: 'Текст за показване',
        url: 'URL адрес',
        openInNewWindow: 'Отвори в нов прозорец',
      },
      table: {
        table: 'Таблица',
        addRowAbove: 'Add row above',
        addRowBelow: 'Add row below',
        addColLeft: 'Add column left',
        addColRight: 'Add column right',
        delRow: 'Delete row',
        delCol: 'Delete column',
        delTable: 'Delete table',
      },
      hr: {
        insert: 'Добави хоризонтална линия',
      },
      style: {
        style: 'Стил',
        p: 'Нормален',
        blockquote: 'Цитат',
        pre: 'Код',
        h1: 'Заглавие 1',
        h2: 'Заглавие 2',
        h3: 'Заглавие 3',
        h4: 'Заглавие 4',
        h5: 'Заглавие 5',
        h6: 'Заглавие 6',
      },
      lists: {
        unordered: 'Символен списък',
        ordered: 'Цифров списък',
      },
      options: {
        help: 'Помощ',
        fullscreen: 'На цял екран',
        codeview: 'Преглед на код',
      },
      paragraph: {
        paragraph: 'Параграф',
        outdent: 'Намаляване на отстъпа',
        indent: 'Абзац',
        left: 'Подравняване в ляво',
        center: 'Център',
        right: 'Подравняване в дясно',
        justify: 'Разтягане по ширина',
      },
      color: {
        recent: 'Последния избран цвят',
        more: 'Още цветове',
        background: 'Цвят на фона',
        foreground: 'Цвят на шрифта',
        transparent: 'Прозрачен',
        setTransparent: 'Направете прозрачен',
        reset: 'Възстанови',
        resetToDefault: 'Възстанови оригиналните',
        cpSelect: 'Изберете',
      },
      shortcut: {
        shortcuts: 'Клавишни комбинации',
        close: 'Затвори',
        textFormatting: 'Форматиране на текста',
        action: 'Действие',
        paragraphFormatting: 'Форматиране на параграф',
        documentStyle: 'Стил на документа',
        extraKeys: 'Extra keys',
      },
      help: {
        'insertParagraph': 'Insert Paragraph',
        'undo': 'Undoes the last command',
        'redo': 'Redoes the last command',
        'tab': 'Tab',
        'untab': 'Untab',
        'bold': 'Set a bold style',
        'italic': 'Set a italic style',
        'underline': 'Set a underline style',
        'strikethrough': 'Set a strikethrough style',
        'removeFormat': 'Clean a style',
        'justifyLeft': 'Set left align',
        'justifyCenter': 'Set center align',
        'justifyRight': 'Set right align',
        'justifyFull': 'Set full align',
        'insertUnorderedList': 'Toggle unordered list',
        'insertOrderedList': 'Toggle ordered list',
        'outdent': 'Outdent on current paragraph',
        'indent': 'Indent on current paragraph',
        'formatPara': 'Change current block\'s format as a paragraph(P tag)',
        'formatH1': 'Change current block\'s format as H1',
        'formatH2': 'Change current block\'s format as H2',
        'formatH3': 'Change current block\'s format as H3',
        'formatH4': 'Change current block\'s format as H4',
        'formatH5': 'Change current block\'s format as H5',
        'formatH6': 'Change current block\'s format as H6',
        'insertHorizontalRule': 'Insert horizontal rule',
        'linkDialog.show': 'Show Link Dialog',
      },
      history: {
        undo: 'Назад',
        redo: 'Напред',
      },
      specialChar: {
        specialChar: 'SPECIAL CHARACTERS',
        select: 'Select Special characters',
      },
    },
  });
})(jQuery);
<commit_msg>Update summernote-bg-BG.js<commit_after>(function($) {
  $.extend($.summernote.lang, {
    'bg-BG': {
      font: {
        bold: 'Удебелен',
        italic: 'Наклонен',
        underline: 'Подчертан',
        clear: 'Изчисти стиловете',
        height: 'Височина',
        name: 'Шрифт',
        strikethrough: 'Задраскано',
        subscript: 'Долен индекс',
        superscript: 'Горен индекс',
        size: 'Размер на шрифта',
      },
      image: {
        image: 'Изображение',
        insert: 'Постави картинка',
        resizeFull: 'Цял размер',
        resizeHalf: 'Размер на 50%',
        resizeQuarter: 'Размер на 25%',
        floatLeft: 'Подравни в ляво',
        floatRight: 'Подравни в дясно',
        floatNone: 'Без подравняване',
        shapeRounded: 'Форма: Заоблено',
        shapeCircle: 'Форма: Кръг',
        shapeThumbnail: 'Форма: Миниатюра',
        shapeNone: 'Форма: Без',
        dragImageHere: 'Пуснете изображението тук',
        dropImage: 'Пуснете Изображение или Текст',
        selectFromFiles: 'Изберете файл',
        maximumFileSize: 'Максимален размер на файла',
        maximumFileSizeError: 'Достигнат Максимален размер на файла.',
        url: 'URL адрес на изображение',
        remove: 'Премахни изображение',
        original: 'Оригинал',
      },
      video: {
        video: 'Видео',
        videoLink: 'Видео линк',
        insert: 'Добави Видео',
        url: 'Видео URL?',
        providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion or Youku)',
      },
      link: {
        link: 'Връзка',
        insert: 'Добави връзка',
        unlink: 'Премахни връзка',
        edit: 'Промени',
        textToDisplay: 'Текст за показване',
        url: 'URL адрес',
        openInNewWindow: 'Отвори в нов прозорец',
      },
      table: {
        table: 'Таблица',
        addRowAbove: 'Добави ред отгоре',
        addRowBelow: 'Добави ред отдолу',
        addColLeft: 'Добави колона отляво',
        addColRight: 'Добави колона отдясно',
        delRow: 'Изтрии ред',
        delCol: 'Изтрии колона',
        delTable: 'Изтрии таблица',
      },
      hr: {
        insert: 'Добави хоризонтална линия',
      },
      style: {
        style: 'Стил',
        p: 'Нормален',
        blockquote: 'Цитат',
        pre: 'Код',
        h1: 'Заглавие 1',
        h2: 'Заглавие 2',
        h3: 'Заглавие 3',
        h4: 'Заглавие 4',
        h5: 'Заглавие 5',
        h6: 'Заглавие 6',
      },
      lists: {
        unordered: 'Символен списък',
        ordered: 'Цифров списък',
      },
      options: {
        help: 'Помощ',
        fullscreen: 'На цял екран',
        codeview: 'Преглед на код',
      },
      paragraph: {
        paragraph: 'Параграф',
        outdent: 'Намаляване на отстъпа',
        indent: 'Абзац',
        left: 'Подравняване в ляво',
        center: 'Център',
        right: 'Подравняване в дясно',
        justify: 'Разтягане по ширина',
      },
      color: {
        recent: 'Последния избран цвят',
        more: 'Още цветове',
        background: 'Цвят на фона',
        foreground: 'Цвят на шрифта',
        transparent: 'Прозрачен',
        setTransparent: 'Направете прозрачен',
        reset: 'Възстанови',
        resetToDefault: 'Възстанови оригиналните',
        cpSelect: 'Изберете',
      },
      shortcut: {
        shortcuts: 'Клавишни комбинации',
        close: 'Затвори',
        textFormatting: 'Форматиране на текста',
        action: 'Действие',
        paragraphFormatting: 'Форматиране на параграф',
        documentStyle: 'Стил на документа',
        extraKeys: 'Екстра бутони',
      },
      help: {
        'insertParagraph': 'Добави Параграф',
        'undo': 'Отмени последната промяна',
        'redo': 'Върни последната промяна',
        'tab': 'Tab',
        'untab': 'Untab',
        'bold': 'Удебели',
        'italic': 'Приложи наклонен стил',
        'underline': 'Приложи подчераване',
        'strikethrough': 'Приложи зачеркнат стил',
        'removeFormat': 'Изчисти стилове',
        'justifyLeft': 'Подравняване в ляво',
        'justifyCenter': 'Подравняване в центъра',
        'justifyRight': 'Подравняване в дясно',
        'justifyFull': 'Двустранно подравняване',
        'insertUnorderedList': 'Toggle unordered list',
        'insertOrderedList': 'Toggle ordered list',
        'outdent': 'Outdent on current paragraph',
        'indent': 'Indent on current paragraph',
        'formatPara': 'Change current block\'s format as a paragraph(P tag)',
        'formatH1': 'Change current block\'s format as H1',
        'formatH2': 'Change current block\'s format as H2',
        'formatH3': 'Change current block\'s format as H3',
        'formatH4': 'Change current block\'s format as H4',
        'formatH5': 'Change current block\'s format as H5',
        'formatH6': 'Change current block\'s format as H6',
        'insertHorizontalRule': 'Вмъкни хоризонтално правило',
        'linkDialog.show': 'Show Link Dialog',
      },
      history: {
        undo: 'Назад',
        redo: 'Напред',
      },
      specialChar: {
        specialChar: 'SPECIAL CHARACTERS',
        select: 'Избери Специални символи',
      },
    },
  });
})(jQuery);
<|endoftext|>


<commit_before>(function($) {
  $.extend($.summernote.lang, {
    'fr-FR': {
      font: {
        bold: 'Gras',
        italic: 'Italique',
        underline: 'Souligné',
        clear: 'Effacer la mise en forme',
        height: 'Interligne',
        name: 'Famille de police',
        strikethrough: 'Barré',
        superscript: 'Exposant',
        subscript: 'Indice',
        size: 'Taille de police'
      },
      image: {
        image: 'Image',
        insert: 'Insérer une image',
        resizeFull: 'Taille originale',
        resizeHalf: 'Redimensionner à 50 %',
        resizeQuarter: 'Redimensionner à 25 %',
        floatLeft: 'Aligné à gauche',
        floatRight: 'Aligné à droite',
        floatNone: 'Pas d\'alignement',
        shapeRounded: 'Forme: Rectangle arrondie',
        shapeCircle: 'Forme: Cercle',
        shapeThumbnail: 'Forme: Vignette',
        shapeNone: 'Forme: Aucune',
        dragImageHere: 'Faites glisser une image ou un texte dans ce cadre',
        dropImage: 'Lachez l\'image ou le texte',
        selectFromFiles: 'Choisir un fichier',
        maximumFileSize: 'Taille de fichier maximale',
        maximumFileSizeError: 'Taille maximale du fichier dépassée',
        url: 'URL de l\'image',
        remove: 'Supprimer l\'image',
        original: 'Original'
      },
      video: {
        video: 'Vidéo',
        videoLink: 'Lien vidéo',
        insert: 'Insérer une vidéo',
        url: 'URL de la vidéo',
        providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion ou Youku)'
      },
      link: {
        link: 'Lien',
        insert: 'Insérer un lien',
        unlink: 'Supprimer un lien',
        edit: 'Modifier',
        textToDisplay: 'Texte à afficher',
        url: 'URL du lien',
        openInNewWindow: 'Ouvrir dans une nouvelle fenêtre'
      },
      table: {
        table: 'Tableau',
        addRowAbove: 'Ajouter une ligne au-dessus',
        addRowBelow: 'Ajouter une ligne en dessous',
        addColLeft: 'Ajouter une colonne à gauche',
        addColRight: 'Ajouter une colonne à droite',
        delRow: 'Supprimer la ligne',
        delCol: 'Supprimer la colonne',
        delTable: 'Supprimer le tableau'
      },
      hr: {
        insert: 'Insérer une ligne horizontale'
      },
      style: {
        style: 'Style',
        p: 'Normal',
        blockquote: 'Citation',
        pre: 'Code source',
        h1: 'Titre 1',
        h2: 'Titre 2',
        h3: 'Titre 3',
        h4: 'Titre 4',
        h5: 'Titre 5',
        h6: 'Titre 6'
      },
      lists: {
        unordered: 'Liste à puces',
        ordered: 'Liste numérotée'
      },
      options: {
        help: 'Aide',
        fullscreen: 'Plein écran',
        codeview: 'Afficher le code HTML'
      },
      paragraph: {
        paragraph: 'Paragraphe',
        outdent: 'Diminuer le retrait',
        indent: 'Augmenter le retrait',
        left: 'Aligner à gauche',
        center: 'Centrer',
        right: 'Aligner à droite',
        justify: 'Justifier'
      },
      color: {
        recent: 'Dernière couleur sélectionnée',
        more: 'Plus de couleurs',
        background: 'Couleur de fond',
        foreground: 'Couleur de police',
        transparent: 'Transparent',
        setTransparent: 'Définir la transparence',
        reset: 'Restaurer',
        resetToDefault: 'Restaurer la couleur par défaut'
      },
      shortcut: {
        shortcuts: 'Raccourcis',
        close: 'Fermer',
        textFormatting: 'Mise en forme du texte',
        action: 'Action',
        paragraphFormatting: 'Mise en forme des paragraphes',
        documentStyle: 'Style du document',
        extraKeys: 'Touches supplémentaires'
      },
      help: {
        'insertParagraph': 'Insérer paragraphe',
        'undo': 'Défaire la dernière commande',
        'redo': 'Refaire la dernière commande',
        'tab': 'Tabulation',
        'untab': 'Tabulation arrière',
        'bold': 'Mettre en caractère gras',
        'italic': 'Mettre en italique',
        'underline': 'Mettre en souligné',
        'strikethrough': 'Mettre en texte barré',
        'removeFormat': 'Nettoyer les styles',
        'justifyLeft': 'Aligner à gauche',
        'justifyCenter': 'Centrer',
        'justifyRight': 'Aligner à droite',
        'justifyFull': 'Justifier à gauche et à droite',
        'insertUnorderedList': 'Basculer liste à puces',
        'insertOrderedList': 'Basculer liste ordonnée',
        'outdent': 'Diminuer le retrait du paragraphe',
        'indent': 'Augmenter le retrait du paragraphe',
        'formatPara': 'Changer le paragraphe en cours en normal (P)',
        'formatH1': 'Changer le paragraphe en cours en entête H1',
        'formatH2': 'Changer le paragraphe en cours en entête H2',
        'formatH3': 'Changer le paragraphe en cours en entête H3',
        'formatH4': 'Changer le paragraphe en cours en entête H4',
        'formatH5': 'Changer le paragraphe en cours en entête H5',
        'formatH6': 'Changer le paragraphe en cours en entête H6',
        'insertHorizontalRule': 'Insérer séparation horizontale',
        'linkDialog.show': 'Afficher fenêtre d\'hyperlien'
      },
      history: {
        undo: 'Annuler la dernière action',
        redo: 'Restaurer la dernière action annulée'
      },
      specialChar: {
        specialChar: 'CARACTÈRES SPÉCIAUX',
        select: 'Choisir des caractères spéciaux'
      }
    }
  });
})(jQuery);
<commit_msg>Typo<commit_after>(function($) {
  $.extend($.summernote.lang, {
    'fr-FR': {
      font: {
        bold: 'Gras',
        italic: 'Italique',
        underline: 'Souligné',
        clear: 'Effacer la mise en forme',
        height: 'Interligne',
        name: 'Famille de police',
        strikethrough: 'Barré',
        superscript: 'Exposant',
        subscript: 'Indice',
        size: 'Taille de police'
      },
      image: {
        image: 'Image',
        insert: 'Insérer une image',
        resizeFull: 'Taille originale',
        resizeHalf: 'Redimensionner à 50 %',
        resizeQuarter: 'Redimensionner à 25 %',
        floatLeft: 'Aligné à gauche',
        floatRight: 'Aligné à droite',
        floatNone: 'Pas d\'alignement',
        shapeRounded: 'Forme: Rectangle arrondi',
        shapeCircle: 'Forme: Cercle',
        shapeThumbnail: 'Forme: Vignette',
        shapeNone: 'Forme: Aucune',
        dragImageHere: 'Faites glisser une image ou un texte dans ce cadre',
        dropImage: 'Lachez l\'image ou le texte',
        selectFromFiles: 'Choisir un fichier',
        maximumFileSize: 'Taille de fichier maximale',
        maximumFileSizeError: 'Taille maximale du fichier dépassée',
        url: 'URL de l\'image',
        remove: 'Supprimer l\'image',
        original: 'Original'
      },
      video: {
        video: 'Vidéo',
        videoLink: 'Lien vidéo',
        insert: 'Insérer une vidéo',
        url: 'URL de la vidéo',
        providers: '(YouTube, Vimeo, Vine, Instagram, DailyMotion ou Youku)'
      },
      link: {
        link: 'Lien',
        insert: 'Insérer un lien',
        unlink: 'Supprimer un lien',
        edit: 'Modifier',
        textToDisplay: 'Texte à afficher',
        url: 'URL du lien',
        openInNewWindow: 'Ouvrir dans une nouvelle fenêtre'
      },
      table: {
        table: 'Tableau',
        addRowAbove: 'Ajouter une ligne au-dessus',
        addRowBelow: 'Ajouter une ligne en dessous',
        addColLeft: 'Ajouter une colonne à gauche',
        addColRight: 'Ajouter une colonne à droite',
        delRow: 'Supprimer la ligne',
        delCol: 'Supprimer la colonne',
        delTable: 'Supprimer le tableau'
      },
      hr: {
        insert: 'Insérer une ligne horizontale'
      },
      style: {
        style: 'Style',
        p: 'Normal',
        blockquote: 'Citation',
        pre: 'Code source',
        h1: 'Titre 1',
        h2: 'Titre 2',
        h3: 'Titre 3',
        h4: 'Titre 4',
        h5: 'Titre 5',
        h6: 'Titre 6'
      },
      lists: {
        unordered: 'Liste à puces',
        ordered: 'Liste numérotée'
      },
      options: {
        help: 'Aide',
        fullscreen: 'Plein écran',
        codeview: 'Afficher le code HTML'
      },
      paragraph: {
        paragraph: 'Paragraphe',
        outdent: 'Diminuer le retrait',
        indent: 'Augmenter le retrait',
        left: 'Aligner à gauche',
        center: 'Centrer',
        right: 'Aligner à droite',
        justify: 'Justifier'
      },
      color: {
        recent: 'Dernière couleur sélectionnée',
        more: 'Plus de couleurs',
        background: 'Couleur de fond',
        foreground: 'Couleur de police',
        transparent: 'Transparent',
        setTransparent: 'Définir la transparence',
        reset: 'Restaurer',
        resetToDefault: 'Restaurer la couleur par défaut'
      },
      shortcut: {
        shortcuts: 'Raccourcis',
        close: 'Fermer',
        textFormatting: 'Mise en forme du texte',
        action: 'Action',
        paragraphFormatting: 'Mise en forme des paragraphes',
        documentStyle: 'Style du document',
        extraKeys: 'Touches supplémentaires'
      },
      help: {
        'insertParagraph': 'Insérer paragraphe',
        'undo': 'Défaire la dernière commande',
        'redo': 'Refaire la dernière commande',
        'tab': 'Tabulation',
        'untab': 'Tabulation arrière',
        'bold': 'Mettre en caractère gras',
        'italic': 'Mettre en italique',
        'underline': 'Mettre en souligné',
        'strikethrough': 'Mettre en texte barré',
        'removeFormat': 'Nettoyer les styles',
        'justifyLeft': 'Aligner à gauche',
        'justifyCenter': 'Centrer',
        'justifyRight': 'Aligner à droite',
        'justifyFull': 'Justifier à gauche et à droite',
        'insertUnorderedList': 'Basculer liste à puces',
        'insertOrderedList': 'Basculer liste ordonnée',
        'outdent': 'Diminuer le retrait du paragraphe',
        'indent': 'Augmenter le retrait du paragraphe',
        'formatPara': 'Changer le paragraphe en cours en normal (P)',
        'formatH1': 'Changer le paragraphe en cours en entête H1',
        'formatH2': 'Changer le paragraphe en cours en entête H2',
        'formatH3': 'Changer le paragraphe en cours en entête H3',
        'formatH4': 'Changer le paragraphe en cours en entête H4',
        'formatH5': 'Changer le paragraphe en cours en entête H5',
        'formatH6': 'Changer le paragraphe en cours en entête H6',
        'insertHorizontalRule': 'Insérer séparation horizontale',
        'linkDialog.show': 'Afficher fenêtre d\'hyperlien'
      },
      history: {
        undo: 'Annuler la dernière action',
        redo: 'Restaurer la dernière action annulée'
      },
      specialChar: {
        specialChar: 'CARACTÈRES SPÉCIAUX',
        select: 'Choisir des caractères spéciaux'
      }
    }
  });
})(jQuery);
<|endoftext|>


<commit_before>/// <reference path="../typings/jquery/jquery.d.ts"/>
/// <reference path="../typings/d3/d3.d.ts"/>
/// <reference path="../typings/jquery/jquery.d.ts"/>
//######################################################################
//########    Date slider (more complex than it looks)
//######################################################################
var startDate = new Date("2007");
var endDate = new Date("2016");
var selectedDate = new Date("2011");

//------------------------------------------
var diffY = endDate.getFullYear() - startDate.getFullYear() + 1;
var tickvals = [];
var ticknames = [];
var canvasWidth = $('#chart').width();
var canvasHeight = $('#chart').height();

for (var i = 0; i < diffY; i++) {
    tickvals[i] = i * 12;
    ticknames[i] = "" + (startDate.getFullYear() + i);
}

$('#ex1').slider({
    formatter: function (value) {
        return 'Current value: ' + value;
    }
});

function slided() {
    Update();
}

var dateSlider = $("#ex13").slider({
    ticks: tickvals,
    ticks_labels: ticknames,
    ticks_snap_bounds: 0,
    min: 0,
    max: diffY * 12,
    step: 1,
    value: 2,
    formatter: function (value) {
        var dd = new Date(startDate.toUTCString());
        dd.setMonth(dd.getMonth() + value);
        return dd.toDateString().slice(4);
    },
}).on('slide', slided).data('slider');
dateSlider.setValue(48);

//######################################################################
//########    Main Update functions
//######################################################################

function Update() {
    //Do we have data?
    if (graphdata === undefined) {
        return;
    }

    selectedDate = new Date(startDate.toUTCString());
    selectedDate.setMonth(selectedDate.getMonth() + dateSlider.getValue());
    selected_method.SetData(graphdata);
    selected_method.SetDate(selectedDate);

    selected_method.Update();
}

$(window).resize(resize);

function resize() {
    canvasWidth = $('#chart').width();
    canvasHeight = $('#chart').height();
    selected_method.Redraw(canvasWidth, canvasHeight);
}

//######################################################################
//########    Data Picking, Validating, Loading
//######################################################################
var graphdata;
var stockData = [{ name: "Les Miserables", url: "/data/miserables.json" },
    { name: "Napier Publications", url: "/data/napierPublications.json" },
        { name: "freeScaleTime-300-1.4", url: "/data/freeScaleTime-300-1.4.json" },
            { name: "freeScaleTime-300-1.9", url: "/data/freeScaleTime-300-1.9.json" },
    ];
var loadedData = [];
ChangeData("Les Miserables");
//dropdown selector ------------
$("#datapicker").html("");
for (i = 0; i < stockData.length; i++) {
    $("#datapicker").append("<option>" + stockData[i].name + "</option>");
}

$("#datapicker").on('change', function () {
    ChangeData($("#datapicker").val());
    Update();
});

function ChangeData(dataName) {
    //loaded?
    console.log("changing Data to: " + dataName);
    for (i = 0; i < loadedData.length; i++) {
        if (loadedData[i].name == dataName) {
            //yep, set and bail.
            InitChannelMixer(loadedData[i]);
            graphdata = loadedData[i].data;
            //channelPanel
            Update();
            return;
        }
    }
    //no, load it
    var url = "";
    for (i = 0; i < stockData.length; i++) {
        if (stockData[i].name == dataName) {
            url = stockData[i].url;
            break;
        }
    }
    if (url == "") {
        //this isn't stock data
        console.error("Can't load custom url data yet :(");
        return;
    }

    console.log("Loading Data");
    d3.json(url, function (error, graph) {
        if (error) {
            console.error(error);
        } else {
            console.log("Loaded");
            var nodekeys = Object.keys(graph.nodes[0]);
            var linkkeys = Object.keys(graph.links[0]);
            loadedData.push({ name: dataName, data: graph, url: url,nodekeys:nodekeys,linkkeys:linkkeys });
            ChangeData(dataName);
        }
    });
}
function InitChannelMixer(data) {
    var cp = $("#channelPanel");
    cp.html("");
    $("#channelPanelHeadder").html(
        "DataSet: " + data.name +
        ", Nodes / Links: " + data.data.nodes.length + " / " + data.data.links.length
        );
    $('
', { 'class': 'row' }).html(
        "Node Attributes: " + data.nodekeys +
        ", Link Attributes: " + data.linkkeys
        ).appendTo(cp);

    var lkeydiv = $('
', { 'class': 'col-sm-6' })
        .text("hello worl4d")
        .appendTo(cp);
    var nkeydiv = $('
', { 'class': 'col-sm-6' })
        .text("hello worl4d")
        .appendTo(cp);
     var linkDropdown = $();
     /*
     for (var key in data.nodekeys) {
           $("div", { 'class': 'methodParam' }).html(key)
           .append( $("div", { 'class': 'selectpicker','data-width':'75%' }).html(key)

           )
     }*/
    // dropdowns
}
//######################################################################
//########    Method Picking, Validating, Loading
//######################################################################
var methods = [];
var m_simple = new method_simple();
methods.push(m_simple);
var selected_method;
changeMethod(m_simple);

//dropdown selector ------------
$("#methodpicker").html("");
for (i = 0; i < methods.length; i++) {
    $("#methodpicker").append("<option>" + methods[i].name + "</option>");
}
$("#methodpicker").on('change', function () {
    changeMethod($("#methodpicker").val());
});

function VerifyMethodParmeters(method) {
    var mustHaveParams = ["name", "ptype", "pval"];
    var acceptedParams = ["slider", "checkbox", "textbox"];

    for (var i in method.parameters) {
        var param = method.parameters[i];
        for (var j in mustHaveParams) {
            var str = mustHaveParams[j];
            if (!param.hasOwnProperty(str)) {
                console.error("Method '" + method.name + "', parameter '" + param.name + "', must have a '" + str + "' member!");
                return false;
            }
        }

        if ($.inArray(param.ptype, acceptedParams) == -1) {
            console.error("Method '" + method.name + "', Unkown parameter type : " + param.name + " - " + param.ptype);
        }

    }
    return true;
}

function changeMethod(methodName) {
    if (typeof (methodName) === "string") {
        var find = $.grep(methods, function (e) {
            return e.name == methodName
        });
        if (find.length == 1) {
            selected_method = find[0];
        } else if (find.length > 1) {
            console.error("Multiple methods registered with the name:" + methodName);
            return;
        } else {
            console.error("Can't find method with name: " + methodName);
            return;
        }
    } else {
        if (!methodName.hasOwnProperty("name")) {
            console.error("Unkown object type passed to changeMethod");
            return;
        }
        selected_method = methodName;
    }
    resize();
    selected_method.SetDateBounds(startDate, endDate);

    //clear param div
    var pdiv1 = $('#paramDiv1').html("");
    var pdiv2 = $('#paramDiv2').html("");
    var pdiv;

    console.log("Loading Method: " + selected_method.name);
    if (!selected_method.hasOwnProperty("parameters")) {
        console.log("Method: " + selected_method.name + " has no parameters");
        return;
    }

    //verify parameters
    if (!VerifyMethodParmeters(selected_method)) {
        return;
    }

    for (var i in selected_method.parameters) {
        //toggle placement div
        if (pdiv == pdiv1) {
            pdiv = pdiv2;
        } else {
            pdiv = pdiv1;
        }
        var param = selected_method.parameters[i];
        var newdiv = $("
");
        switch (param.ptype) {

            case "slider":
                newdiv.append("
" + param.name + "
");
                var sliderDiv = $("<input id=" + param.name + " data-slider-id='ex1Slider' type='text' data-slider-min=" + param.minval + " data-slider-max=" + param.maxval + " data-slider-step=" + param.step + " data-slider-value=" + param.pval + " />");
                newdiv.append(sliderDiv);
                sliderDiv.slider();
                //register calback using some legit hax
                ! function outer(pp) {
                    sliderDiv.change('slide', function inner(e) {
                        pp.pval = e.value.newValue;
                        selected_method.ParamChanged(pp);
                    });
                } (param);
                break;

            case "checkbox":
                var boxDiv = $("<input  id=" + param.name + " type='checkbox' " + (param.pval ? "checked" : "") + ">");
                newdiv.append(boxDiv).append("  " + param.name);
                ! function outer(pp, bb) {
                    boxDiv.change(function inner() {
                        pp.pval = bb.is(":checked");
                        selected_method.ParamChanged(pp);
                    });
                } (param, boxDiv);
                break;

            case "textbox":
                newdiv.append("
" + param.name + "
");
                var igroup = $("

");
                var input = $("<input type='text class='form-control'>");
                igroup.append(input);
                var span = $("");
                var btn = $("<button class='btn btn-default btn-sm' type='button'>Go!</button>");
                newdiv.append(igroup.append(span.append(btn)));
                ! function outer(pp, bb) {
                    btn.click(function inner() {
                        pp.pval = bb.val();
                        selected_method.ParamChanged(pp);
                    });
                } (param, input);
                break;

            default:
                console.error("Unkown method parameter type : " + param.name + " - " + param.ptype);
                break;
        }
        pdiv.append(newdiv);
    }
    pdiv.hide().show(0);
}<commit_msg>Fixing data link path for live demo<commit_after>/// <reference path="../typings/jquery/jquery.d.ts"/>
/// <reference path="../typings/d3/d3.d.ts"/>
/// <reference path="../typings/jquery/jquery.d.ts"/>
//######################################################################
//########    Date slider (more complex than it looks)
//######################################################################
var startDate = new Date("2007");
var endDate = new Date("2016");
var selectedDate = new Date("2011");

//------------------------------------------
var diffY = endDate.getFullYear() - startDate.getFullYear() + 1;
var tickvals = [];
var ticknames = [];
var canvasWidth = $('#chart').width();
var canvasHeight = $('#chart').height();

for (var i = 0; i < diffY; i++) {
    tickvals[i] = i * 12;
    ticknames[i] = "" + (startDate.getFullYear() + i);
}

$('#ex1').slider({
    formatter: function (value) {
        return 'Current value: ' + value;
    }
});

function slided() {
    Update();
}

var dateSlider = $("#ex13").slider({
    ticks: tickvals,
    ticks_labels: ticknames,
    ticks_snap_bounds: 0,
    min: 0,
    max: diffY * 12,
    step: 1,
    value: 2,
    formatter: function (value) {
        var dd = new Date(startDate.toUTCString());
        dd.setMonth(dd.getMonth() + value);
        return dd.toDateString().slice(4);
    },
}).on('slide', slided).data('slider');
dateSlider.setValue(48);

//######################################################################
//########    Main Update functions
//######################################################################

function Update() {
    //Do we have data?
    if (graphdata === undefined) {
        return;
    }

    selectedDate = new Date(startDate.toUTCString());
    selectedDate.setMonth(selectedDate.getMonth() + dateSlider.getValue());
    selected_method.SetData(graphdata);
    selected_method.SetDate(selectedDate);

    selected_method.Update();
}

$(window).resize(resize);

function resize() {
    canvasWidth = $('#chart').width();
    canvasHeight = $('#chart').height();
    selected_method.Redraw(canvasWidth, canvasHeight);
}

//######################################################################
//########    Data Picking, Validating, Loading
//######################################################################
var graphdata;
var stockData = [{ name: "Les Miserables", url: "data/miserables.json" },
    { name: "Napier Publications", url: "data/napierPublications.json" },
        { name: "freeScaleTime-300-1.4", url: "data/freeScaleTime-300-1.4.json" },
            { name: "freeScaleTime-300-1.9", url: "sata/freeScaleTime-300-1.9.json" },
    ];
var loadedData = [];
ChangeData("Les Miserables");
//dropdown selector ------------
$("#datapicker").html("");
for (i = 0; i < stockData.length; i++) {
    $("#datapicker").append("<option>" + stockData[i].name + "</option>");
}

$("#datapicker").on('change', function () {
    ChangeData($("#datapicker").val());
    Update();
});

function ChangeData(dataName) {
    //loaded?
    console.log("changing Data to: " + dataName);
    for (i = 0; i < loadedData.length; i++) {
        if (loadedData[i].name == dataName) {
            //yep, set and bail.
            InitChannelMixer(loadedData[i]);
            graphdata = loadedData[i].data;
            //channelPanel
            Update();
            return;
        }
    }
    //no, load it
    var url = "";
    for (i = 0; i < stockData.length; i++) {
        if (stockData[i].name == dataName) {
            url = stockData[i].url;
            break;
        }
    }
    if (url == "") {
        //this isn't stock data
        console.error("Can't load custom url data yet :(");
        return;
    }

    console.log("Loading Data");
    d3.json(url, function (error, graph) {
        if (error) {
            console.error(error);
        } else {
            console.log("Loaded");
            var nodekeys = Object.keys(graph.nodes[0]);
            var linkkeys = Object.keys(graph.links[0]);
            loadedData.push({ name: dataName, data: graph, url: url,nodekeys:nodekeys,linkkeys:linkkeys });
            ChangeData(dataName);
        }
    });
}
function InitChannelMixer(data) {
    var cp = $("#channelPanel");
    cp.html("");
    $("#channelPanelHeadder").html(
        "DataSet: " + data.name +
        ", Nodes / Links: " + data.data.nodes.length + " / " + data.data.links.length
        );
    $('
', { 'class': 'row' }).html(
        "Node Attributes: " + data.nodekeys +
        ", Link Attributes: " + data.linkkeys
        ).appendTo(cp);

    var lkeydiv = $('
', { 'class': 'col-sm-6' })
        .text("hello worl4d")
        .appendTo(cp);
    var nkeydiv = $('
', { 'class': 'col-sm-6' })
        .text("hello worl4d")
        .appendTo(cp);
     var linkDropdown = $();
     /*
     for (var key in data.nodekeys) {
           $("div", { 'class': 'methodParam' }).html(key)
           .append( $("div", { 'class': 'selectpicker','data-width':'75%' }).html(key)

           )
     }*/
    // dropdowns
}
//######################################################################
//########    Method Picking, Validating, Loading
//######################################################################
var methods = [];
var m_simple = new method_simple();
methods.push(m_simple);
var selected_method;
changeMethod(m_simple);

//dropdown selector ------------
$("#methodpicker").html("");
for (i = 0; i < methods.length; i++) {
    $("#methodpicker").append("<option>" + methods[i].name + "</option>");
}
$("#methodpicker").on('change', function () {
    changeMethod($("#methodpicker").val());
});

function VerifyMethodParmeters(method) {
    var mustHaveParams = ["name", "ptype", "pval"];
    var acceptedParams = ["slider", "checkbox", "textbox"];

    for (var i in method.parameters) {
        var param = method.parameters[i];
        for (var j in mustHaveParams) {
            var str = mustHaveParams[j];
            if (!param.hasOwnProperty(str)) {
                console.error("Method '" + method.name + "', parameter '" + param.name + "', must have a '" + str + "' member!");
                return false;
            }
        }

        if ($.inArray(param.ptype, acceptedParams) == -1) {
            console.error("Method '" + method.name + "', Unkown parameter type : " + param.name + " - " + param.ptype);
        }

    }
    return true;
}

function changeMethod(methodName) {
    if (typeof (methodName) === "string") {
        var find = $.grep(methods, function (e) {
            return e.name == methodName
        });
        if (find.length == 1) {
            selected_method = find[0];
        } else if (find.length > 1) {
            console.error("Multiple methods registered with the name:" + methodName);
            return;
        } else {
            console.error("Can't find method with name: " + methodName);
            return;
        }
    } else {
        if (!methodName.hasOwnProperty("name")) {
            console.error("Unkown object type passed to changeMethod");
            return;
        }
        selected_method = methodName;
    }
    resize();
    selected_method.SetDateBounds(startDate, endDate);

    //clear param div
    var pdiv1 = $('#paramDiv1').html("");
    var pdiv2 = $('#paramDiv2').html("");
    var pdiv;

    console.log("Loading Method: " + selected_method.name);
    if (!selected_method.hasOwnProperty("parameters")) {
        console.log("Method: " + selected_method.name + " has no parameters");
        return;
    }

    //verify parameters
    if (!VerifyMethodParmeters(selected_method)) {
        return;
    }

    for (var i in selected_method.parameters) {
        //toggle placement div
        if (pdiv == pdiv1) {
            pdiv = pdiv2;
        } else {
            pdiv = pdiv1;
        }
        var param = selected_method.parameters[i];
        var newdiv = $("
");
        switch (param.ptype) {

            case "slider":
                newdiv.append("
" + param.name + "
");
                var sliderDiv = $("<input id=" + param.name + " data-slider-id='ex1Slider' type='text' data-slider-min=" + param.minval + " data-slider-max=" + param.maxval + " data-slider-step=" + param.step + " data-slider-value=" + param.pval + " />");
                newdiv.append(sliderDiv);
                sliderDiv.slider();
                //register calback using some legit hax
                ! function outer(pp) {
                    sliderDiv.change('slide', function inner(e) {
                        pp.pval = e.value.newValue;
                        selected_method.ParamChanged(pp);
                    });
                } (param);
                break;

            case "checkbox":
                var boxDiv = $("<input  id=" + param.name + " type='checkbox' " + (param.pval ? "checked" : "") + ">");
                newdiv.append(boxDiv).append("  " + param.name);
                ! function outer(pp, bb) {
                    boxDiv.change(function inner() {
                        pp.pval = bb.is(":checked");
                        selected_method.ParamChanged(pp);
                    });
                } (param, boxDiv);
                break;

            case "textbox":
                newdiv.append("
" + param.name + "
");
                var igroup = $("

");
                var input = $("<input type='text class='form-control'>");
                igroup.append(input);
                var span = $("");
                var btn = $("<button class='btn btn-default btn-sm' type='button'>Go!</button>");
                newdiv.append(igroup.append(span.append(btn)));
                ! function outer(pp, bb) {
                    btn.click(function inner() {
                        pp.pval = bb.val();
                        selected_method.ParamChanged(pp);
                    });
                } (param, input);
                break;

            default:
                console.error("Unkown method parameter type : " + param.name + " - " + param.ptype);
                break;
        }
        pdiv.append(newdiv);
    }
    pdiv.hide().show(0);
}<|endoftext|>


<commit_before>define(['app', 'factories/stream', 'directives/radialProgressBar', 'directives/timeSince', 'directives/duration',
        'filters/escape', 'filters/wordwrap', 'modules/pagination', 'ngInfiniteScroll'], function(app) {
  app.controller('buildDetailsCtrl', ['$scope', 'initialData', '$http', '$routeParams', 'stream', 'pagination', function($scope, initialData, $http, $routeParams, Stream, Pagination) {
    'use strict';

    var stream,
        entrypoint = '/api/0/builds/' + $routeParams.build_id + '/';

    function sortTests(arr) {
      var resultScore = {
        'errored': 1100,
        'failed': 1000,
        'skipped': 200,
        'passed': 100
      }

      function getScore(object) {
        return [resultScore[object.result.id] || 500, object.duration];
      }

      arr.sort(function(a, b){
        var a_score = getScore(a),
            b_score = getScore(b);
        if (a_score[0] < b_score[0]) {
          return 1
        }
        if (a_score[0] > b_score[0]) {
          return -1
        }
        if (a_score[1] < b_score[1]) {
          return 1
        }
        if (a_score[1] > b_score[1]) {
          return -1
        }
        if (a_score[2] < b_score[2]) {
          return 1
        }
        if (a_score[2] > b_score[2]) {
          return -1
        }
        return 0;
      });

      return arr;
    }

    $scope.build = initialData.data.build;
    $scope.phases = initialData.data.phase;
    $scope.tests = sortTests(initialData.data.tests);
    $scope.testsPaginator = Pagination.create($scope.tests);

    function updateBuild(data){
      $scope.$apply(function() {
        $scope.build = data;
      });
    }

    function addTest(data) {
      $scope.$apply(function() {
        var updated = false,
            item_id = data.id,
            attr, result, item;

        if ($scope.tests.length > 0) {
          result = $.grep($scope.tests, function(e){ return e.id == item_id; });
          if (result.length > 0) {
            item = result[0];
            for (attr in data) {
              item[attr] = data[attr];
            }
            updated = true;
          }
        }
        if (!updated) {
          $scope.tests.unshift(data);
        }
      });
    }

    $scope.getTestStatus = function() {
      if ($scope.build.status.id == "finished") {
        if ($scope.tests.length === 0) {
          return "no-results";
        } else {
          return "has-results";
        }
      }
      return "pending";
    };

    stream = Stream($scope, entrypoint);
    stream.subscribe('build.update', updateBuild);
    stream.subscribe('test.update', addTest);
  }]);
});
<commit_msg>Remove infinite scroll module references<commit_after>define(['app', 'factories/stream', 'directives/radialProgressBar', 'directives/timeSince', 'directives/duration',
        'filters/escape', 'filters/wordwrap', 'modules/pagination'], function(app) {
  app.controller('buildDetailsCtrl', ['$scope', 'initialData', '$http', '$routeParams', 'stream', 'pagination', function($scope, initialData, $http, $routeParams, Stream, Pagination) {
    'use strict';

    var stream,
        entrypoint = '/api/0/builds/' + $routeParams.build_id + '/';

    function sortTests(arr) {
      var resultScore = {
        'errored': 1100,
        'failed': 1000,
        'skipped': 200,
        'passed': 100
      }

      function getScore(object) {
        return [resultScore[object.result.id] || 500, object.duration];
      }

      arr.sort(function(a, b){
        var a_score = getScore(a),
            b_score = getScore(b);
        if (a_score[0] < b_score[0]) {
          return 1
        }
        if (a_score[0] > b_score[0]) {
          return -1
        }
        if (a_score[1] < b_score[1]) {
          return 1
        }
        if (a_score[1] > b_score[1]) {
          return -1
        }
        if (a_score[2] < b_score[2]) {
          return 1
        }
        if (a_score[2] > b_score[2]) {
          return -1
        }
        return 0;
      });

      return arr;
    }

    $scope.build = initialData.data.build;
    $scope.phases = initialData.data.phase;
    $scope.tests = sortTests(initialData.data.tests);
    $scope.testsPaginator = Pagination.create($scope.tests);

    function updateBuild(data){
      $scope.$apply(function() {
        $scope.build = data;
      });
    }

    function addTest(data) {
      $scope.$apply(function() {
        var updated = false,
            item_id = data.id,
            attr, result, item;

        if ($scope.tests.length > 0) {
          result = $.grep($scope.tests, function(e){ return e.id == item_id; });
          if (result.length > 0) {
            item = result[0];
            for (attr in data) {
              item[attr] = data[attr];
            }
            updated = true;
          }
        }
        if (!updated) {
          $scope.tests.unshift(data);
        }
      });
    }

    $scope.getTestStatus = function() {
      if ($scope.build.status.id == "finished") {
        if ($scope.tests.length === 0) {
          return "no-results";
        } else {
          return "has-results";
        }
      }
      return "pending";
    };

    stream = Stream($scope, entrypoint);
    stream.subscribe('build.update', updateBuild);
    stream.subscribe('test.update', addTest);
  }]);
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { View } from 'react-native';

import { addComponent, removeComponent, updateQuery } from '@appbaseio/reactivecore/lib/actions';
import { isEqual, checkValueChange } from '@appbaseio/reactivecore/lib/utils/helper';

import types from '@appbaseio/reactivecore/lib/utils/types';

class DataController extends Component {
	componentDidMount() {
		this.locked = false;
		this.props.addComponent(this.props.componentId);

		if (this.props.defaultSelected) {
			this.updateQuery(this.props.defaultSelected, this.props);
		} else {
			this.updateQuery(null, this.props);
		}
	}

	componentWillReceiveProps(nextProps) {
		if (!this.locked) {
			if (!isEqual(this.props.defaultSelected, nextProps.defaultSelected)) {
				this.updateQuery(nextProps.defaultSelected, nextProps);
			} else if (!isEqual(this.props.selectedValue, nextProps.selectedValue)) {
				this.updateQuery(nextProps.selectedValue, nextProps);
			}
		}
	}

	componentWillUnmount() {
		this.props.removeComponent(this.props.componentId);
	}

	defaultQuery() {
		return {
			match_all: {},
		};
	}

	updateQuery = (defaultSelected = null, props) => {
		this.locked = true;
		const query = props.customQuery ? props.customQuery : this.defaultQuery;
		let onQueryChange = null;
		if (props.onQueryChange) {
			onQueryChange = props.onQueryChange;
		}

		const performUpdate = () => {
			props.updateQuery({
				componentId: props.componentId,
				query: query(defaultSelected, props),
				value: defaultSelected,
				label: props.filterLabel,
				showFilter: props.showFilter,
				onQueryChange,
				URLParams: false,
			});
			this.locked = false;
		};

		checkValueChange(
			props.componentId,
			defaultSelected,
			props.beforeValueChange,
			props.onValueChange,
			performUpdate,
		);
	};

	render() {
		return (
			<View style={this.props.style} className={this.props.className}>
				{this.props.children}
			</View>
		);
	}
}

DataController.defaultProps = {
	showFilter: true,
	style: {},
	className: null,
};

DataController.propTypes = {
	componentId: types.stringRequired,
	addComponent: types.funcRequired,
	// DataController can accept any defaultSelected depending on the query used
	defaultSelected: types.any, // eslint-disable-line
	selectedValue: types.selectedValue,
	removeComponent: types.funcRequired,
	beforeValueChange: types.func,
	onValueChange: types.func,
	customQuery: types.func,
	onQueryChange: types.func,
	updateQuery: types.funcRequired,
	filterLabel: types.string,
	showFilter: types.bool,
	children: types.children,
	style: types.style,
	className: types.string,
};

const mapStateToProps = (state, props) => ({
	selectedValue:
		(state.selectedValues[props.componentId]
			&& state.selectedValues[props.componentId].value)
		|| null,
});

const mapDispatchtoProps = dispatch => ({
	addComponent: component => dispatch(addComponent(component)),
	removeComponent: component => dispatch(removeComponent(component)),
	updateQuery: updateQueryObject => dispatch(updateQuery(updateQueryObject)),
});

export default connect(mapStateToProps, mapDispatchtoProps)(DataController);
<commit_msg>native: datacontroller linting fixes<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { View } from 'react-native';

import { addComponent, removeComponent, updateQuery } from '@appbaseio/reactivecore/lib/actions';
import { isEqual, checkValueChange } from '@appbaseio/reactivecore/lib/utils/helper';

import types from '@appbaseio/reactivecore/lib/utils/types';

class DataController extends Component {
	componentDidMount() {
		this.locked = false;
		this.props.addComponent(this.props.componentId);

		if (this.props.defaultSelected) {
			this.updateQuery(this.props.defaultSelected, this.props);
		} else {
			this.updateQuery(null, this.props);
		}
	}

	componentWillReceiveProps(nextProps) {
		if (!this.locked) {
			if (!isEqual(this.props.defaultSelected, nextProps.defaultSelected)) {
				this.updateQuery(nextProps.defaultSelected, nextProps);
			} else if (!isEqual(this.props.selectedValue, nextProps.selectedValue)) {
				this.updateQuery(nextProps.selectedValue, nextProps);
			}
		}
	}

	componentWillUnmount() {
		this.props.removeComponent(this.props.componentId);
	}

	defaultQuery() {
		return {
			match_all: {},
		};
	}

	updateQuery = (defaultSelected = null, props) => {
		this.locked = true;
		const query = props.customQuery ? props.customQuery : this.defaultQuery;
		let onQueryChange = null;
		if (props.onQueryChange) {
			onQueryChange = props.onQueryChange;
		}

		const performUpdate = () => {
			props.updateQuery({
				componentId: props.componentId,
				query: query(defaultSelected, props),
				value: defaultSelected,
				label: props.filterLabel,
				showFilter: props.showFilter,
				onQueryChange,
				URLParams: false,
			});
			this.locked = false;
		};

		checkValueChange(
			props.componentId,
			defaultSelected,
			props.beforeValueChange,
			props.onValueChange,
			performUpdate,
		);
	};

	render() {
		return (
			<View style={this.props.style} className={this.props.className}>
				{this.props.children}
			</View>
		);
	}
}

DataController.defaultProps = {
	showFilter: true,
	style: {},
	className: null,
};

DataController.propTypes = {
	componentId: types.stringRequired,
	addComponent: types.funcRequired,
	// DataController can accept any defaultSelected depending on the query used
	defaultSelected: types.any, // eslint-disable-line
	selectedValue: types.selectedValue,
	removeComponent: types.funcRequired,
	beforeValueChange: types.func,
	onValueChange: types.func,
	customQuery: types.func,
	onQueryChange: types.func,
	updateQuery: types.funcRequired,
	filterLabel: types.string,
	showFilter: types.bool,
	children: types.children,
	style: types.style,
	className: types.string,
};

const mapStateToProps = (state, props) => ({
	selectedValue: (
		state.selectedValues[props.componentId]
		&& state.selectedValues[props.componentId].value
	) || null,
});

const mapDispatchtoProps = dispatch => ({
	addComponent: component => dispatch(addComponent(component)),
	removeComponent: component => dispatch(removeComponent(component)),
	updateQuery: updateQueryObject => dispatch(updateQuery(updateQueryObject)),
});

export default connect(mapStateToProps, mapDispatchtoProps)(DataController);
<|endoftext|>


<commit_before>this.t = function(key, ...replaces) {
	if (_.isObject(replaces[0])) {
		return TAPi18n.__(key, replaces);
	} else {
		return TAPi18n.__(key, {
			postProcess: 'sprintf',
			sprintf: replaces
		});
	}
};

this.tr = function(key, options, ...replaces) {
	if (_.isObject(replaces[0])) {
		return TAPi18n.__(key, options, replaces);
	} else {
		return TAPi18n.__(key, options, {
			postProcess: 'sprintf',
			sprintf: replaces
		});
	}
};

this.isRtl = (language) => language != null && ['ar', 'dv', 'fa', 'he', 'ku', 'ps', 'sd', 'ug', 'ur', 'yi'].includes(language.split('-').shift().toLowerCase());
<commit_msg>fix sidebar and rtl<commit_after>this.t = function(key, ...replaces) {
	if (_.isObject(replaces[0])) {
		return TAPi18n.__(key, replaces);
	} else {
		return TAPi18n.__(key, {
			postProcess: 'sprintf',
			sprintf: replaces
		});
	}
};

this.tr = function(key, options, ...replaces) {
	if (_.isObject(replaces[0])) {
		return TAPi18n.__(key, options, replaces);
	} else {
		return TAPi18n.__(key, options, {
			postProcess: 'sprintf',
			sprintf: replaces
		});
	}
};

this.isRtl = (lang) => {
	const language = lang ? lang : localStorage.getItem('userLanguage');
	return ['ar', 'dv', 'fa', 'he', 'ku', 'ps', 'sd', 'ug', 'ur', 'yi'].includes(language.split('-').shift().toLowerCase());
};
<|endoftext|>


<commit_before>module.exports = {
  "japan":"http://blog.openstreetmap.de/wp-uploads//2015/10/jp.svg",
  "france":"http://blog.openstreetmap.de/wp-uploads//2016/02/fr.svg",
  "spain":"http://blog.openstreetmap.de/wp-uploads//2015/01/es.svg",
  "czech republic":"http://blog.openstreetmap.de/wp-uploads//2015/01/cz.svg",
  "russia":"http://blog.openstreetmap.de/wp-uploads//2016/01/ru.svg",
  "romania":"http://blog.openstreetmap.de/wp-uploads//2015/10/ro.svg",
  "netherland":"http://blog.openstreetmap.de/wp-uploads//2015/07/nl.svg",
  "brasil":"http://blog.openstreetmap.de/wp-uploads//2015/01/pt-br.svg",
  "poland":"http://blog.openstreetmap.de/wp-uploads//2015/10/pl.svg",
  "taiwan":"http://blog.openstreetmap.de/wp-uploads//2016/01/tw.svg",
  "switzerland":"http://blog.openstreetmap.de/wp-uploads//2016/01/ch.svg",
  "schweiz":"http://blog.openstreetmap.de/wp-uploads//2016/01/ch.svg",
  "italia":"http://blog.openstreetmap.de/wp-uploads//2016/01/it.svg",
  "italy":"http://blog.openstreetmap.de/wp-uploads//2016/01/it.svg",
  "us":"http://blog.openstreetmap.de/wp-uploads//2016/01/us.svg",
  "united states":"http://blog.openstreetmap.de/wp-uploads//2016/01/us.svg",
  "austria":"http://blog.openstreetmap.de/wp-uploads//2016/01/at.svg",
  "österreich":"http://blog.openstreetmap.de/wp-uploads//2016/02/at.svg",
  "philippines":"http://blog.openstreetmap.de/wp-uploads//2016/01/ph.svg",
  "belgium":"http://blog.openstreetmap.de/wp-uploads//2016/01/be-1.svg",
  "argentina":"http://blog.openstreetmap.de/wp-uploads//2016/01/ar.svg",
  "england":"http://blog.openstreetmap.de/wp-uploads//2015/01/en.svg",
  "uk":"http://blog.openstreetmap.de/wp-uploads//2015/01/en.svg",
  "germany":"http://blog.openstreetmap.de/wp-uploads//2016/01/de.svg",
  "deutschland":"http://blog.openstreetmap.de/wp-uploads//2016/01/de.svg",
  "bolivia":"http://blog.openstreetmap.de/wp-uploads//2016/01/bo.svg",
   "canada":"http://blog.openstreetmap.de/wp-uploads//2016/01/ca.svg",
   "hungary":"http://blog.openstreetmap.de/wp-uploads//2016/02/hu.svg",c
   "india":"http://blog.openstreetmap.de/wp-uploads//2016/01/in.svg",
  "colombia":"http://blog.openstreetmap.de/wp-uploads//2016/02/co.svg"

};
<commit_msg>Fix error.<commit_after>module.exports = {
  "japan":"http://blog.openstreetmap.de/wp-uploads//2015/10/jp.svg",
  "france":"http://blog.openstreetmap.de/wp-uploads//2016/02/fr.svg",
  "spain":"http://blog.openstreetmap.de/wp-uploads//2015/01/es.svg",
  "czech republic":"http://blog.openstreetmap.de/wp-uploads//2015/01/cz.svg",
  "russia":"http://blog.openstreetmap.de/wp-uploads//2016/01/ru.svg",
  "romania":"http://blog.openstreetmap.de/wp-uploads//2015/10/ro.svg",
  "netherland":"http://blog.openstreetmap.de/wp-uploads//2015/07/nl.svg",
  "brasil":"http://blog.openstreetmap.de/wp-uploads//2015/01/pt-br.svg",
  "poland":"http://blog.openstreetmap.de/wp-uploads//2015/10/pl.svg",
  "taiwan":"http://blog.openstreetmap.de/wp-uploads//2016/01/tw.svg",
  "switzerland":"http://blog.openstreetmap.de/wp-uploads//2016/01/ch.svg",
  "schweiz":"http://blog.openstreetmap.de/wp-uploads//2016/01/ch.svg",
  "italia":"http://blog.openstreetmap.de/wp-uploads//2016/01/it.svg",
  "italy":"http://blog.openstreetmap.de/wp-uploads//2016/01/it.svg",
  "us":"http://blog.openstreetmap.de/wp-uploads//2016/01/us.svg",
  "united states":"http://blog.openstreetmap.de/wp-uploads//2016/01/us.svg",
  "austria":"http://blog.openstreetmap.de/wp-uploads//2016/01/at.svg",
  "österreich":"http://blog.openstreetmap.de/wp-uploads//2016/02/at.svg",
  "philippines":"http://blog.openstreetmap.de/wp-uploads//2016/01/ph.svg",
  "belgium":"http://blog.openstreetmap.de/wp-uploads//2016/01/be-1.svg",
  "argentina":"http://blog.openstreetmap.de/wp-uploads//2016/01/ar.svg",
  "england":"http://blog.openstreetmap.de/wp-uploads//2015/01/en.svg",
  "uk":"http://blog.openstreetmap.de/wp-uploads//2015/01/en.svg",
  "germany":"http://blog.openstreetmap.de/wp-uploads//2016/01/de.svg",
  "deutschland":"http://blog.openstreetmap.de/wp-uploads//2016/01/de.svg",
  "bolivia":"http://blog.openstreetmap.de/wp-uploads//2016/01/bo.svg",
  "canada":"http://blog.openstreetmap.de/wp-uploads//2016/01/ca.svg",
  "hungary":"http://blog.openstreetmap.de/wp-uploads//2016/02/hu.svg",
  "india":"http://blog.openstreetmap.de/wp-uploads//2016/01/in.svg",
  "colombia":"http://blog.openstreetmap.de/wp-uploads//2016/02/co.svg"

};
<|endoftext|>


<commit_before>// Copyright (c) 2013 M-Way Solutions GmbH
// http://github.com/mwaylabs/The-M-Project/blob/absinthe/MIT-LICENSE.txt

/**
 * The M.BikiniStore is used to connect a model collection to an
 * bikini server.
 *
 * This will give you an online and offline store with live data updates.
 *
 * @module M.BikiniStore
 *
 * @type {*}
 * @extends M.Store
 *
 * @example
 *
 * // The default configuration will save the complete model data as a json,
 * // and the offline change log to a local WebSql database, synchronize it
 * // trough REST calls with the server and receive live updates via a socket.io connection.
 *
 * var MyCollection = M.Collection.extend({
 *      model: MyModel,
 *      url: 'http://myBikiniServer.com:8200/bikini/myCollection',
 *      store: new M.BikiniStore( {
 *          useLocalStore:   true, // (default) store the data for offline use
 *          useSocketNotify: true, // (default) register at the server for live updates
 *          useOfflineChanges: true // (default) allow changes to the offline data
 *      })
 * });
 *
 */
M.BikiniStore = M.Store.extend({

    _type: 'M.BikiniStore',

    _transactionFailed: false,

    _selector: null,

    endpoints: {},

    options: null,

    localStore: M.WebSqlStore,

    useLocalStore: true,

    useSocketNotify: true,

    useOfflineChanges: true,

    typeMapping: {
        'binary': 'text',
        'date': 'string'
    },

    initialize: function( options ) {
        M.Store.prototype.initialize.apply(this, arguments);
        this.options = this.options || {};
        this.options.useLocalStore = this.useLocalStore;
        this.options.useSocketNotify = this.useSocketNotify;
        this.options.useOfflineChanges = this.useOfflineChanges;
        this.options.socketPath = this.socketPath;
        this.options.localStore = this.localStore;
        this.options.typeMapping = this.typeMapping;
        _.extend(this.options, options || {});
    },

    initModel: function( model ) {
    },

    initCollection: function( collection ) {
        var url = collection.getUrlRoot();
        var entity = this.getEntity(collection.entity);
        if( url && entity ) {
            var name = entity.name;
            var idAttribute = entity.idAttribute;
            var hash = this._hashCode(url);
            var credentials = entity.credentials || collection.credentials;
            var user = credentials && credentials.username ? credentials.username : '';
            var channel = name + user + hash;
            collection.channel = channel;
            // get or create endpoint for this url
            var that = this;
            var endpoint = this.endpoints[hash];
            if( !endpoint ) {
                var href = M.Request.getLocation(url);
                endpoint = {};
                endpoint.baseUrl = url;
                endpoint.readUrl = collection.getUrl();
                endpoint.host = href.protocol + '//' + href.host;
                endpoint.path = href.pathname;
                endpoint.entity = entity;
                endpoint.channel = channel;
                endpoint.credentials = credentials;
                endpoint.socketPath = this.options.socketPath;
                endpoint.localStore = this.createLocalStore(endpoint);
                endpoint.messages = this.createMsgCollection(endpoint);
                endpoint.socket = this.createSocket(endpoint, collection);
                endpoint.info = this.fetchServerInfo(endpoint, collection);
                that.endpoints[hash] = endpoint;
            }
            collection.endpoint = endpoint;
            collection.listenTo(this, endpoint.channel, this.onMessage, collection);
            if( endpoint.messages && !endpoint.socket ) {
                that.sendMessages(endpoint, collection);
            }
        }
    },

    getEndpoint: function( url ) {
        if( url ) {
            var hash = this._hashCode(url);
            return this.endpoints[hash];
        }
    },

    createLocalStore: function( endpoint, idAttribute ) {
        if( this.options.useLocalStore && endpoint ) {
            var entities = {};
            entities[endpoint.entity.name] = {
                name: endpoint.channel,
                idAttribute: idAttribute
            };
            return new this.options.localStore({
                entities: entities
            });
        }
    },

    createMsgCollection: function( endpoint ) {
        if( this.options.useOfflineChange && endpoint ) {
            var name = 'msg-' + endpoint.channel;
            var MsgCollection = M.Collection.extend({
                model: M.Model.extend({ idAttribute: '_id' })
            });
            var messages = new MsgCollection({
                entity: name,
                store: new this.options.localStore()
            });
            messages.fetch();
            return messages;
        }
    },

    createSocket: function( endpoint, collection, name ) {
        if( this.options.useSocketNotify && endpoint.socketPath && endpoint ) {
            var path = endpoint.path;
            path = endpoint.socketPath || (path + (path.charAt(path.length - 1) === '/' ? '' : '/' ) + 'live');
            // remove leading /
            var resource = (path && path.indexOf('/') === 0) ? path.substr(1) : path;
            var that = this;
            var socket = M.SocketIO.create({
                host: endpoint.host,
                resource: resource,
                connected: function() {
                    that._bindChannel(socket, endpoint, name);
                    that.sendMessages(endpoint, collection);
                }
            });
            return socket;
        }
    },

    _bindChannel: function( socket, endpoint, name ) {
        var that = this;
        var channel = endpoint.channel;
        var time = this.getLastMessageTime(channel);
        name = name || endpoint.entity.name;
        socket.on(channel, function( msg ) {
            if( msg ) {
                that.setLastMessageTime(channel, msg.time);
                that.trigger(channel, msg);
            }
        });
        socket.emit('bind', {
            entity: name,
            channel: channel,
            time: time
        });
    },

    getLastMessageTime: function( channel ) {
        return localStorage.getItem('__' + channel + 'last_msg_time') || 0;
    },

    setLastMessageTime: function( channel, time ) {
        if( time ) {
            localStorage.setItem('__' + channel + 'last_msg_time', time);
        }
    },

    _hashCode: function( str ) {
        var hash = 0, char;
        if( str.length === 0 ) {
            return hash;
        }
        for( var i = 0, l = str.length; i < l; i++ ) {
            char = str.charCodeAt(i);
            hash = ((hash << 5) - hash) + char;
            hash |= 0; // Convert to 32bit integer
        }
        return hash;
    },

    onMessage: function( msg ) {
        if( msg && msg.method ) {
            var localStore = this.endpoint ? this.endpoint.localStore : null;
            var options = { store: localStore, merge: true, fromMessage: true, entity: this.entity, parse: true };
            var attrs = msg.data;

            switch( msg.method ) {
                case 'patch':
                case 'update':
                case 'create':
                    options.patch = msg.method === 'patch';
                    var model = msg.id ? this.get(msg.id) : null;
                    if( model ) {
                        model.save(attrs, options);
                    } else {
                        this.create(attrs, options);
                    }
                    break;
                case 'delete':
                    if( msg.id ) {
                        if( msg.id === 'all' ) {
                            while((model = this.first())) {
                                if( localStore ) {
                                    localStore.sync.apply(this, ['delete', model, { store: localStore, fromMessage: true } ]);
                                }
                                this.remove(model);
                            }
                            this.store.setLastMessageTime(this.endpoint.channel, '');
                        } else {
                            var msgModel = this.get(msg.id);
                            if( msgModel ) {
                                msgModel.destroy(options);
                            }
                        }
                    }
                    break;

                default:
                    break;
            }
        }
    },

    sync: function( method, model, options ) {
        var that = options.store || this.store;
        if( options.fromMessage ) {
            return that.handleCallback(options.success);
        }
        var endpoint = that.getEndpoint(this.getUrlRoot());
        if( that && endpoint ) {
            var channel = this.channel;

            if( M.isModel(model) && !model.id ) {
                model.set(model.idAttribute, new M.ObjectID().toHexString());
            }

            var time = that.getLastMessageTime(channel);
            // only send read messages if no other store can do this
            // or for initial load
            if( method !== 'read' || !endpoint.localStore || !time ) {
                // do backbone rest
                that.addMessage(method, model, // we don't need to call callbacks if an other store handle this
                    endpoint.localStore ? {} : options, endpoint);
            } else if( method === 'read' && time ) {
                that.fetchChanges(endpoint, time);
            }
            if( endpoint.localStore ) {
                options.store = endpoint.localStore;
                endpoint.localStore.sync.apply(this, arguments);
            }
        }
    },

    addMessage: function( method, model, options, endpoint ) {
        var that = this;
        if( method && model ) {
            var changes = model.changedSinceSync;
            var data = null;
            var storeMsg = false;
            switch( method ) {
                case 'update':
                case 'create':
                    data = options.attrs || model.toJSON();
                    storeMsg = true;
                    break;
                case 'patch':
                    if( _.isEmpty(changes) ) {
                        return;
                    }
                    data = model.toJSON({ attrs: changes });
                    storeMsg = true;
                    break;
                case 'delete':
                    storeMsg = true;
                    break;
            }
            var msg = {
                _id: model.id,
                id: model.id,
                method: method,
                data: data
            };
            var emit = function( endpoint, msg ) {
                that.emitMessage(endpoint, msg, options, model);
            };
            if( storeMsg ) {
                this.storeMessage(endpoint, msg, emit);
            } else {
                emit(endpoint, msg);
            }
        }
    },

    emitMessage: function( endpoint, msg, options, model ) {
        var channel = endpoint.channel;
        var that = this;
        var url = M.isModel(model) || msg.method !== 'read' ? endpoint.baseUrl : endpoint.readUrl;
        if( msg.id && msg.method !== 'create' ) {
            url += '/' + msg.id;
        }
        model.sync.apply(model, [msg.method, model, {
            url: url,
            error: function( xhr, status ) {
                if( !xhr.responseText && that.options.useOfflineChange ) {
                    // this seams to be only a connection problem, so we keep the message an call success
                    that.handleCallback(options.success, msg.data);
                } else {
                    that.removeMessage(endpoint, msg, function( endpoint, msg ) {
                        // Todo: revert changed data
                        that.handleCallback(options.error, status);
                    });
                }
            },
            success: function( data ) {
                that.removeMessage(endpoint, msg, function( endpoint, msg ) {
                    if( options.success ) {
                        var resp = data;
                        that.handleCallback(options.success, resp);
                    } else {
                        // that.setLastMessageTime(channel, msg.time);
                        if( msg.method === 'read' ) {
                            var array = _.isArray(data) ? data : [ data ];
                            for( var i = 0; i < array.length; i++ ) {
                                data = array[i];
                                if( data ) {
                                    that.trigger(channel, {
                                        id: data._id,
                                        method: 'update',
                                        data: data
                                    });
                                }
                            }
                        } else {
                            that.trigger(channel, msg);
                        }
                    }
                });
            },
            store: {}
        }]);
    },

    fetchChanges: function( endpoint, time ) {
        var that = this;
        if( endpoint && endpoint.baseUrl && time ) {
            var changes = new M.Collection({});
            changes.fetch({
                url: endpoint.baseUrl + '/changes/' + time,
                success: function() {
                    changes.each(function( msg ) {
                        if( msg.time && msg.method ) {
                            that.setLastMessageTime(endpoint.channel, msg.time);
                            that.trigger(endpoint.channel, msg);
                        }
                    });
                },
                credentials: endpoint.credentials
            });
        }
    },

    fetchServerInfo: function( endpoint, collection ) {
        var that = this;
        if( endpoint && endpoint.baseUrl ) {
            var info = new M.Model();
            var time = that.getLastMessageTime(endpoint.channel);
            info.fetch({
                url: endpoint.baseUrl + '/info',
                success: function() {
                    if( !time && info.get('time') ) {
                        that.setLastMessageTime(endpoint.channel, info.get('time'));
                    }
                    if( !endpoint.socketPath && info.get('socketPath') ) {
                        endpoint.socketPath = info.get('socketPath');
                        var name = info.get('entity') || endpoint.entity.name;
                        if( that.options.useSocketNotify ) {
                            that.createSocket(endpoint, collection, name);
                        }
                    }
                },
                credentials: endpoint.credentials
            });
        }
    },

    sendMessages: function( endpoint, collection ) {
        if( endpoint && endpoint.messages && collection ) {
            var that = this;
            endpoint.messages.each(function( message ) {
                var msg;
                try {
                    msg = JSON.parse(message.get('msg'));
                } catch( e ) {
                }
                var channel = message.get('channel');
                if( msg && channel ) {
                    var model = that.createModel({ collection: collection }, msg.data);
                    that.emitMessage(endpoint, msg, {}, model);
                } else {
                    message.destroy();
                }
            });
        }
    },

    mergeMessages: function( data, id ) {
        return data;
    },

    storeMessage: function( endpoint, msg, callback ) {
        if( endpoint && endpoint.messages && msg ) {
            var channel = endpoint.channel;
            var message = endpoint.messages.get(msg._id);
            if( message ) {
                var oldMsg = JSON.parse(message.get('msg'));
                message.save({
                    msg: JSON.stringify(_.extend(oldMsg, msg))
                });
            } else {
                endpoint.messages.create({
                    _id: msg._id,
                    id: msg.id,
                    msg: JSON.stringify(msg),
                    channel: channel
                });
            }
        }
        callback(endpoint, msg);
    },

    removeMessage: function( endpoint, msg, callback ) {
        if( endpoint && endpoint.messages ) {
            var message = endpoint.messages.get(msg._id);
            if( message ) {
                message.destroy();
            }
        }
        callback(endpoint, msg);
    },

    clear: function( collection ) {
        if( collection ) {
            var endpoint = this.getEndpoint(collection.getUrlRoot());
            if( endpoint ) {
                if( endpoint.localStore ) {
                    endpoint.localStore.destroy();
                }
                if( endpoint.messages ) {
                    endpoint.messages.destroy();
                }
                collection.reset();
                this.setLastMessageTime(endpoint.channel, '');
            }
        }
    }

});
<commit_msg>fix for bikini useOfflineChanges<commit_after>// Copyright (c) 2013 M-Way Solutions GmbH
// http://github.com/mwaylabs/The-M-Project/blob/absinthe/MIT-LICENSE.txt

/**
 * The M.BikiniStore is used to connect a model collection to an
 * bikini server.
 *
 * This will give you an online and offline store with live data updates.
 *
 * @module M.BikiniStore
 *
 * @type {*}
 * @extends M.Store
 *
 * @example
 *
 * // The default configuration will save the complete model data as a json,
 * // and the offline change log to a local WebSql database, synchronize it
 * // trough REST calls with the server and receive live updates via a socket.io connection.
 *
 * var MyCollection = M.Collection.extend({
 *      model: MyModel,
 *      url: 'http://myBikiniServer.com:8200/bikini/myCollection',
 *      store: new M.BikiniStore( {
 *          useLocalStore:   true, // (default) store the data for offline use
 *          useSocketNotify: true, // (default) register at the server for live updates
 *          useOfflineChanges: true // (default) allow changes to the offline data
 *      })
 * });
 *
 */
M.BikiniStore = M.Store.extend({

    _type: 'M.BikiniStore',

    _transactionFailed: false,

    _selector: null,

    endpoints: {},

    options: null,

    localStore: M.WebSqlStore,

    useLocalStore: true,

    useSocketNotify: true,

    useOfflineChanges: true,

    typeMapping: {
        'binary': 'text',
        'date': 'string'
    },

    initialize: function( options ) {
        M.Store.prototype.initialize.apply(this, arguments);
        this.options = this.options || {};
        this.options.useLocalStore = this.useLocalStore;
        this.options.useSocketNotify = this.useSocketNotify;
        this.options.useOfflineChanges = this.useOfflineChanges;
        this.options.socketPath = this.socketPath;
        this.options.localStore = this.localStore;
        this.options.typeMapping = this.typeMapping;
        _.extend(this.options, options || {});
    },

    initModel: function( model ) {
    },

    initCollection: function( collection ) {
        var url = collection.getUrlRoot();
        var entity = this.getEntity(collection.entity);
        if( url && entity ) {
            var name = entity.name;
            var idAttribute = entity.idAttribute;
            var hash = this._hashCode(url);
            var credentials = entity.credentials || collection.credentials;
            var user = credentials && credentials.username ? credentials.username : '';
            var channel = name + user + hash;
            collection.channel = channel;
            // get or create endpoint for this url
            var that = this;
            var endpoint = this.endpoints[hash];
            if( !endpoint ) {
                var href = M.Request.getLocation(url);
                endpoint = {};
                endpoint.baseUrl = url;
                endpoint.readUrl = collection.getUrl();
                endpoint.host = href.protocol + '//' + href.host;
                endpoint.path = href.pathname;
                endpoint.entity = entity;
                endpoint.channel = channel;
                endpoint.credentials = credentials;
                endpoint.socketPath = this.options.socketPath;
                endpoint.localStore = this.createLocalStore(endpoint);
                endpoint.messages = this.createMsgCollection(endpoint);
                endpoint.socket = this.createSocket(endpoint, collection);
                endpoint.info = this.fetchServerInfo(endpoint, collection);
                that.endpoints[hash] = endpoint;
            }
            collection.endpoint = endpoint;
            collection.listenTo(this, endpoint.channel, this.onMessage, collection);
            if( endpoint.messages && !endpoint.socket ) {
                that.sendMessages(endpoint, collection);
            }
        }
    },

    getEndpoint: function( url ) {
        if( url ) {
            var hash = this._hashCode(url);
            return this.endpoints[hash];
        }
    },

    createLocalStore: function( endpoint, idAttribute ) {
        if( this.options.useLocalStore && endpoint ) {
            var entities = {};
            entities[endpoint.entity.name] = {
                name: endpoint.channel,
                idAttribute: idAttribute
            };
            return new this.options.localStore({
                entities: entities
            });
        }
    },

    createMsgCollection: function( endpoint ) {
        if( this.options.useOfflineChanges && endpoint ) {
            var name = 'msg-' + endpoint.channel;
            var MsgCollection = M.Collection.extend({
                model: M.Model.extend({ idAttribute: '_id' })
            });
            var messages = new MsgCollection({
                entity: name,
                store: new this.options.localStore()
            });
            messages.fetch();
            return messages;
        }
    },

    createSocket: function( endpoint, collection, name ) {
        if( this.options.useSocketNotify && endpoint.socketPath && endpoint ) {
            var path = endpoint.path;
            path = endpoint.socketPath || (path + (path.charAt(path.length - 1) === '/' ? '' : '/' ) + 'live');
            // remove leading /
            var resource = (path && path.indexOf('/') === 0) ? path.substr(1) : path;
            var that = this;
            var socket = M.SocketIO.create({
                host: endpoint.host,
                resource: resource,
                connected: function() {
                    that._bindChannel(socket, endpoint, name);
                    that.sendMessages(endpoint, collection);
                }
            });
            return socket;
        }
    },

    _bindChannel: function( socket, endpoint, name ) {
        var that = this;
        var channel = endpoint.channel;
        var time = this.getLastMessageTime(channel);
        name = name || endpoint.entity.name;
        socket.on(channel, function( msg ) {
            if( msg ) {
                that.setLastMessageTime(channel, msg.time);
                that.trigger(channel, msg);
            }
        });
        socket.emit('bind', {
            entity: name,
            channel: channel,
            time: time
        });
    },

    getLastMessageTime: function( channel ) {
        return localStorage.getItem('__' + channel + 'last_msg_time') || 0;
    },

    setLastMessageTime: function( channel, time ) {
        if( time ) {
            localStorage.setItem('__' + channel + 'last_msg_time', time);
        }
    },

    _hashCode: function( str ) {
        var hash = 0, char;
        if( str.length === 0 ) {
            return hash;
        }
        for( var i = 0, l = str.length; i < l; i++ ) {
            char = str.charCodeAt(i);
            hash = ((hash << 5) - hash) + char;
            hash |= 0; // Convert to 32bit integer
        }
        return hash;
    },

    onMessage: function( msg ) {
        if( msg && msg.method ) {
            var localStore = this.endpoint ? this.endpoint.localStore : null;
            var options = { store: localStore, merge: true, fromMessage: true, entity: this.entity, parse: true };
            var attrs = msg.data;

            switch( msg.method ) {
                case 'patch':
                case 'update':
                case 'create':
                    options.patch = msg.method === 'patch';
                    var model = msg.id ? this.get(msg.id) : null;
                    if( model ) {
                        model.save(attrs, options);
                    } else {
                        this.create(attrs, options);
                    }
                    break;
                case 'delete':
                    if( msg.id ) {
                        if( msg.id === 'all' ) {
                            while((model = this.first())) {
                                if( localStore ) {
                                    localStore.sync.apply(this, ['delete', model, { store: localStore, fromMessage: true } ]);
                                }
                                this.remove(model);
                            }
                            this.store.setLastMessageTime(this.endpoint.channel, '');
                        } else {
                            var msgModel = this.get(msg.id);
                            if( msgModel ) {
                                msgModel.destroy(options);
                            }
                        }
                    }
                    break;

                default:
                    break;
            }
        }
    },

    sync: function( method, model, options ) {
        var that = options.store || this.store;
        if( options.fromMessage ) {
            return that.handleCallback(options.success);
        }
        var endpoint = that.getEndpoint(this.getUrlRoot());
        if( that && endpoint ) {
            var channel = this.channel;

            if( M.isModel(model) && !model.id ) {
                model.set(model.idAttribute, new M.ObjectID().toHexString());
            }

            var time = that.getLastMessageTime(channel);
            // only send read messages if no other store can do this
            // or for initial load
            if( method !== 'read' || !endpoint.localStore || !time ) {
                // do backbone rest
                that.addMessage(method, model, // we don't need to call callbacks if an other store handle this
                    endpoint.localStore ? {} : options, endpoint);
            } else if( method === 'read' && time ) {
                that.fetchChanges(endpoint, time);
            }
            if( endpoint.localStore ) {
                options.store = endpoint.localStore;
                endpoint.localStore.sync.apply(this, arguments);
            }
        }
    },

    addMessage: function( method, model, options, endpoint ) {
        var that = this;
        if( method && model ) {
            var changes = model.changedSinceSync;
            var data = null;
            var storeMsg = false;
            switch( method ) {
                case 'update':
                case 'create':
                    data = options.attrs || model.toJSON();
                    storeMsg = true;
                    break;
                case 'patch':
                    if( _.isEmpty(changes) ) {
                        return;
                    }
                    data = model.toJSON({ attrs: changes });
                    storeMsg = true;
                    break;
                case 'delete':
                    storeMsg = true;
                    break;
            }
            var msg = {
                _id: model.id,
                id: model.id,
                method: method,
                data: data
            };
            var emit = function( endpoint, msg ) {
                that.emitMessage(endpoint, msg, options, model);
            };
            if( storeMsg ) {
                this.storeMessage(endpoint, msg, emit);
            } else {
                emit(endpoint, msg);
            }
        }
    },

    emitMessage: function( endpoint, msg, options, model ) {
        var channel = endpoint.channel;
        var that = this;
        var url = M.isModel(model) || msg.method !== 'read' ? endpoint.baseUrl : endpoint.readUrl;
        if( msg.id && msg.method !== 'create' ) {
            url += '/' + msg.id;
        }
        model.sync.apply(model, [msg.method, model, {
            url: url,
            error: function( xhr, status ) {
                if( !xhr.responseText && that.options.useOfflineChanges ) {
                    // this seams to be only a connection problem, so we keep the message an call success
                    that.handleCallback(options.success, msg.data);
                } else {
                    that.removeMessage(endpoint, msg, function( endpoint, msg ) {
                        // Todo: revert changed data
                        that.handleCallback(options.error, status);
                    });
                }
            },
            success: function( data ) {
                that.removeMessage(endpoint, msg, function( endpoint, msg ) {
                    if( options.success ) {
                        var resp = data;
                        that.handleCallback(options.success, resp);
                    } else {
                        // that.setLastMessageTime(channel, msg.time);
                        if( msg.method === 'read' ) {
                            var array = _.isArray(data) ? data : [ data ];
                            for( var i = 0; i < array.length; i++ ) {
                                data = array[i];
                                if( data ) {
                                    that.trigger(channel, {
                                        id: data._id,
                                        method: 'update',
                                        data: data
                                    });
                                }
                            }
                        } else {
                            that.trigger(channel, msg);
                        }
                    }
                });
            },
            store: {}
        }]);
    },

    fetchChanges: function( endpoint, time ) {
        var that = this;
        if( endpoint && endpoint.baseUrl && time ) {
            var changes = new M.Collection({});
            changes.fetch({
                url: endpoint.baseUrl + '/changes/' + time,
                success: function() {
                    changes.each(function( msg ) {
                        if( msg.time && msg.method ) {
                            that.setLastMessageTime(endpoint.channel, msg.time);
                            that.trigger(endpoint.channel, msg);
                        }
                    });
                },
                credentials: endpoint.credentials
            });
        }
    },

    fetchServerInfo: function( endpoint, collection ) {
        var that = this;
        if( endpoint && endpoint.baseUrl ) {
            var info = new M.Model();
            var time = that.getLastMessageTime(endpoint.channel);
            info.fetch({
                url: endpoint.baseUrl + '/info',
                success: function() {
                    if( !time && info.get('time') ) {
                        that.setLastMessageTime(endpoint.channel, info.get('time'));
                    }
                    if( !endpoint.socketPath && info.get('socketPath') ) {
                        endpoint.socketPath = info.get('socketPath');
                        var name = info.get('entity') || endpoint.entity.name;
                        if( that.options.useSocketNotify ) {
                            that.createSocket(endpoint, collection, name);
                        }
                    }
                },
                credentials: endpoint.credentials
            });
        }
    },

    sendMessages: function( endpoint, collection ) {
        if( endpoint && endpoint.messages && collection ) {
            var that = this;
            endpoint.messages.each(function( message ) {
                var msg;
                try {
                    msg = JSON.parse(message.get('msg'));
                } catch( e ) {
                }
                var channel = message.get('channel');
                if( msg && channel ) {
                    var model = that.createModel({ collection: collection }, msg.data);
                    that.emitMessage(endpoint, msg, {}, model);
                } else {
                    message.destroy();
                }
            });
        }
    },

    mergeMessages: function( data, id ) {
        return data;
    },

    storeMessage: function( endpoint, msg, callback ) {
        if( endpoint && endpoint.messages && msg ) {
            var channel = endpoint.channel;
            var message = endpoint.messages.get(msg._id);
            if( message ) {
                var oldMsg = JSON.parse(message.get('msg'));
                message.save({
                    msg: JSON.stringify(_.extend(oldMsg, msg))
                });
            } else {
                endpoint.messages.create({
                    _id: msg._id,
                    id: msg.id,
                    msg: JSON.stringify(msg),
                    channel: channel
                });
            }
        }
        callback(endpoint, msg);
    },

    removeMessage: function( endpoint, msg, callback ) {
        if( endpoint && endpoint.messages ) {
            var message = endpoint.messages.get(msg._id);
            if( message ) {
                message.destroy();
            }
        }
        callback(endpoint, msg);
    },

    clear: function( collection ) {
        if( collection ) {
            var endpoint = this.getEndpoint(collection.getUrlRoot());
            if( endpoint ) {
                if( endpoint.localStore ) {
                    endpoint.localStore.destroy();
                }
                if( endpoint.messages ) {
                    endpoint.messages.destroy();
                }
                collection.reset();
                this.setLastMessageTime(endpoint.channel, '');
            }
        }
    }

});
<|endoftext|>