<commit_before>/*
 * This file is to be included by beaver contest tasks, it defines a basic
 * implementation of the main functions of the task object, as well as a grader.
 *
 * Task can overwrite these definitions.
 *
 */

/************************************************************************
 * Untouched parts from beaver-task-1.0.
 ************************************************************************/

var task = {};

task.showViews = function(views, callback) {
   if (views.forum || views.hint || views.editor) {
      //console.error("this task does not have forum, hint nor editor specific view, showing task view instead.");
      views.task = true;
   }
   $.each(['task', 'solution'], function(i, view) {
      if (views[view]) {
         $('#'+view).show();
      } else {
         $('#'+view).hide();
      }
   });
   if (typeof task.hackShowViews === 'function') {task.hackShowViews(views);}
   callback();
};

task.getViews = function(callback) {
    // all beaver tasks have the same views
    var views = {
        task: {},
        solution: {},
        hints: {requires: "task"},
        forum: {requires: "task"},
        editor: {requires: "task"},
        submission: {requires: "task"}
    };
    callback(views);
};

task.updateToken = function(token, callback) {
   callback();
};

task.getHeight = function(callback) {
   callback(parseInt($("html").outerHeight(true)));
};

task.getMetaData = function(callback) {
   if (typeof json !== 'undefined') {
      callback(json);
   } else {
      callback({nbHints:0});
   }
};

/************************************************************************
 * Updated parts in beaver-task-2.0.
 ************************************************************************/

// TODO We update the grader below, if the task has levels. Is this line necessary?
var grader = grader ? grader : {};

function initWrapper(initTaskFor, levels, defaultLevel) {

   // Create a taskFor instance, possibly operating on an existing object.
   function createTask() {
      var taskFor = {};
      taskFor.delayFactory = new DelayFactory();
      taskFor.raphaelFactory = new RaphaelFactory();

      // Simulation factory needs a specific corresponding delay factory.
      // TODO should it expect something else? taskFor? A list of factories?
      taskFor.simulationFactory = new SimulationFactory(taskFor.delayFactory);
      initTaskFor(taskFor);
      return taskFor;
   }

   // Destroy a taskFor instance.
   function destroyTask(taskFor, callback) {
      var doUnload = function() {
         // Order is important.
         taskFor.raphaelFactory.destroyAll();
         taskFor.simulationFactory.destroyAll();
         taskFor.delayFactory.destroyAll();
         if(callback) {
            callback();
         }
      };
      if(levels) {
         taskFor.unloadLevel(doUnload);
      }
      else {
         // TODO Can we assume non-level tasks will imeplement 'unload'?
         taskFor.unload(doUnload);
      }
   }

   // Invoke a function for each level, and wait for callback.
   // When done, invoke finalCallback (optional).
   function callbackLoop(array, itemCallback, finalCallback) {
      var index = 0;
      function innerLoop() {
         if(index >= array.length) {
            if(finalCallback) {
               finalCallback();
            }
            return;
         }
         itemCallback(array[index], function() {
            index++;
            innerLoop();
         });
      }
      innerLoop();
   }

   // Main taskFor instance, for user display.
   var mainTask;

   // The state of the task, including current level and levelState for each level.
   var state = null;

   // Instances of taskFor intended for grading.
   var gradingTasks = {};

   task.load = function(views, callback) {
      mainTask = createTask();
      if(levels) {
         // TODO okay to assume default level is the first level, if not supplied?
         if(defaultLevel === null || defaultLevel === undefined) {
            defaultLevel = levels[0];
         }

         // The objects levelAnswers and levelStates are indexed by level names.
         state = {
            levelAnswers: {},
            levelStates: {},
            level: defaultLevel
         };
         mainTask.loadLevel(state.level, null, views);
         displayHelper.setupLevels();
         callback();
      }
      else {
         // TODO what's the desired behavior when no levels?
         mainTask.load(views, callback);
      }
   };

   task.getState = function(callback) {
      if(levels) {
         // Update state to reflect latest user interaction.
         state.levelStates[state.level] = mainTask.getStateObject();
         state.levelAnswers[state.level] = mainTask.getAnswerObject();
         callback(JSON.stringify(state));
      }
      else {
         // TODO is this the desired behavior? It is from beaver-task-1.0.
         var currentState = {};
         mainTask.getAnswer(function(displayedAnswer) {
            currentState.displayedAnswer = displayedAnswer;
            callback(JSON.stringify(currentState));
         });
      }
   };

   task.getStateObject = function() {
      return state;
   };

   task.reloadAnswer = function(strAnswer, callback) {
      var newAnswer;
      if(strAnswer) {
         newAnswer = JSON.parse(strAnswer);
      }
      else {
         newAnswer = null;
      }
      task.reloadAnswerObject(newAnswer, callback);
   };

   task.reloadAnswerObject = function(newAnswers, callback) {
      if(levels) {
         if (!newAnswers) {
            state.levelAnswers = {};
         }
         else {
            state.levelAnswers = newAnswers;
         }

         // Recreate the main task and load the relevant answer.
         var level = state.level;
         var levelAnswer = state.levelAnswers[level];
         if(levelAnswer === undefined || levelAnswer === null) {
            levelAnswer = mainTask.getDefaultAnswerObject();
            state.levelAnswers[level] = levelAnswer;
         }
         destroyTask(mainTask, function() {
            mainTask = createTask();
            mainTask.loadLevel(level, state.levelStates[level]);
            mainTask.reloadAnswerObject(levelAnswer);
            mainTask.resetDisplay();
            callback();
         });
      }
      else {
         // TODO is this the desired behavior? Taken from beaver-task-1.0.
         if (!newAnswers) {
            mainTask.reloadAnswerObject(mainTask.getDefaultAnswerObject());
         } else {
            mainTask.reloadAnswerObject(JSON.parse(newAnswers));
         }
         callback();
      }
   };

   task.reloadState = function(newStateStr, callback) {
      task.reloadStateObject(JSON.parse(newStateStr), callback);
   };

   task.reloadStateObject = function(newState, callback) {
      if(levels) {
         // Recreate the task to reflect the new state.
         state = newState;
         var level = state.level;
         var levelState = state.levelStates[level];
         destroyTask(mainTask, function() {
            mainTask = createTask();
            mainTask.loadLevel(level, levelState);
            mainTask.reloadAnswerObject(state.levelAnswers[level]);
            callback();
         });
      }
      else {
         // TODO is this the desired behavior? Taken from beaver-task-1.0.
         if (typeof newState.displayedAnswer !== 'undefined') {
            mainTask.reloadAnswer(newState.displayedAnswer, callback);
         }
         else {
            callback();
         }
      }
   };

   task.getDefaultStateObject = function() {
      return {
         level: defaultLevel,
         levelStates: {},
         levelAnswers: {}
      };
   };

   task.getDefaultAnswerObject = function() {
      return {};
   };

   task.getAnswer = function(callback) {
      if(levels) {
         // Update answer to reflect latest user interaction.
         state.levelAnswers[state.level] = mainTask.getAnswerObject();
         callback(JSON.stringify(state.levelAnswers));
      }
      else {
         // TODO is this desired behavior? Taken from beaver-task-1.
         var answerObj = mainTask.getAnswerObject();
         callback(JSON.stringify(answerObj));
      }
   };

   task.getAnswerObject = function() {
      return state.levelAnswers;
   };

   task.unload = function(callback) {
      var instances = [];
      for(var iLevel in gradingTasks) {
         for(var iSeed in gradingTasks[iLevel]) {
            instances.push(gradingTasks[iLevel][iSeed]);
         }
      }
      instances.push(mainTask);
      callbackLoop(instances, function(taskFor, loopCallback) {
         destroyTask(mainTask, loopCallback);
      }, callback);
   };

   function gradeAnswerByLevel(level, seed, levelAnswer, maxScore, callback) {
      // Create grading taskFor instance if it does not exist.
      if(!gradingTasks[level]) {
         gradingTasks[level] = {};
      }
      if(!gradingTasks[level][seed]) {
         var gradingTask = createTask();
         gradingTask.loadLevel(level);
         gradingTasks[level][seed] = gradingTask;
      }

      // Load answer and grade it.
      if(levelAnswer === undefined || levelAnswer === null) {
         levelAnswer = gradingTasks[level][seed].getDefaultAnswerObject();
      }
      gradingTasks[level][seed].reloadAnswerObject(levelAnswer);
      gradingTasks[level][seed].getGrade(function(grade) {
         callback({
            score: Math.round(grade.successRate * maxScore),
            message: grade.message
         });
      });
   }

   // TODO: case where gradeAnswer is called again before it calls its callback
   task.gradeAnswer = function(strAnswer, answerToken, callback, gradedLevel) {
      if(levels) {
         // TODO Can we fetch task params just once instead of every time?
         // If we can, then why do we need to index by seed in graders[level][seed]?
         platform.getTaskParams(null, null, function(taskParams) {
            if (strAnswer === '') {
               callback(taskParams.minScore, '');
               return;
            }

            var seed = taskParams.randomSeed;
            var maxScores = displayHelper.getLevelsMaxScores();

            // TODO generalize this according to list of levels?
            // What can we assume agbout maxScores?
            var gradingMaxScore = {
               easy: maxScores.easy,
               medium: maxScores.medium - maxScores.easy,
               hard: maxScores.hard - maxScores.medium
            };

            var levelAnswers = $.parseJSON(strAnswer);
            var scores = {};
            var messages = {};

            // Grade all levels. If gradedLevel is supplied, skip others.
            callbackLoop(levels, function(level, loopCallback) {
               if(gradedLevel !== null && gradedLevel !== undefined && level !== gradedLevel) {
                  loopCallback();
                  return;
               }
               gradeAnswerByLevel(level, seed, levelAnswers[level], maxScores[level], function(result) {
                  scores[level] = result.score;
                  messages[level] = result.message;
                  loopCallback();
               });
            },
            function() {
               // TODO is this correct? Taken from Arthur's level wrapper.
               if(gradedLevel === null || gradedLevel === undefined) {
                  displayHelper.sendBestScore(callback, scores, messages);
               } else {
                  callback(scores[gradedLevel], messages[gradedLevel]);
               }
            });
         });
      }
      else {
         // TODO What's the correct behavior here with no levels?
      }
   };

   if(levels) {
      // TODO is this the correct behavior?
      grader.gradeTask = task.gradeAnswer;
   }
}

$('document').ready(function() {
   platform.initWithTask(window.task);
});
<commit_msg>Added subTask.display flag and task.displayedSubTask; made subTask.resetDisplay optional.<commit_after>/*
 * This file is to be included by beaver contest tasks, it defines a basic
 * implementation of the main functions of the task object, as well as a grader.
 *
 * Task can overwrite these definitions.
 *
 */

/************************************************************************
 * Untouched parts from beaver-task-1.0.
 ************************************************************************/

var task = {};

task.showViews = function(views, callback) {
   if (views.forum || views.hint || views.editor) {
      //console.error("this task does not have forum, hint nor editor specific view, showing task view instead.");
      views.task = true;
   }
   $.each(['task', 'solution'], function(i, view) {
      if (views[view]) {
         $('#'+view).show();
      } else {
         $('#'+view).hide();
      }
   });
   if (typeof task.hackShowViews === 'function') {task.hackShowViews(views);}
   callback();
};

task.getViews = function(callback) {
    // all beaver tasks have the same views
    var views = {
        task: {},
        solution: {},
        hints: {requires: "task"},
        forum: {requires: "task"},
        editor: {requires: "task"},
        submission: {requires: "task"}
    };
    callback(views);
};

task.updateToken = function(token, callback) {
   callback();
};

task.getHeight = function(callback) {
   callback(parseInt($("html").outerHeight(true)));
};

task.getMetaData = function(callback) {
   if (typeof json !== 'undefined') {
      callback(json);
   } else {
      callback({nbHints:0});
   }
};

/************************************************************************
 * Updated parts in beaver-task-2.0.
 ************************************************************************/

// TODO We update the grader below, if the task has levels. Is this line necessary?
var grader = grader ? grader : {};

function initWrapper(initTaskFor, levels, defaultLevel) {

   // Create a taskFor instance, possibly operating on an existing object.
   function createTask(displayFlag) {
      var taskFor = {};
      taskFor.delayFactory = new DelayFactory();
      taskFor.raphaelFactory = new RaphaelFactory();

      // Simulation factory needs a specific corresponding delay factory.
      // TODO should it expect something else? taskFor? A list of factories?
      taskFor.simulationFactory = new SimulationFactory(taskFor.delayFactory);

      taskFor.display = displayFlag;
      initTaskFor(taskFor);
      return taskFor;
   }

   // Destroy a taskFor instance.
   function destroyTask(taskFor, callback) {
      var doUnload = function() {
         // Order is important.
         taskFor.raphaelFactory.destroyAll();
         taskFor.simulationFactory.destroyAll();
         taskFor.delayFactory.destroyAll();
         if(callback) {
            callback();
         }
      };
      if(levels) {
         taskFor.unloadLevel(doUnload);
      }
      else {
         // TODO Can we assume non-level tasks will imeplement 'unload'?
         taskFor.unload(doUnload);
      }
   }

   // Invoke a function for each level, and wait for callback.
   // When done, invoke finalCallback (optional).
   function callbackLoop(array, itemCallback, finalCallback) {
      var index = 0;
      function innerLoop() {
         if(index >= array.length) {
            if(finalCallback) {
               finalCallback();
            }
            return;
         }
         itemCallback(array[index], function() {
            index++;
            innerLoop();
         });
      }
      innerLoop();
   }

   // Main taskFor instance, for user display.
   var mainTask;

   // The state of the task, including current level and levelState for each level.
   var state = null;

   // Instances of taskFor intended for grading.
   var gradingTasks = {};

   task.load = function(views, callback) {
      mainTask = createTask(true);
      task.displayedSubTask = mainTask;
      if(levels) {
         // TODO okay to assume default level is the first level, if not supplied?
         if(defaultLevel === null || defaultLevel === undefined) {
            defaultLevel = levels[0];
         }

         // The objects levelAnswers and levelStates are indexed by level names.
         state = {
            levelAnswers: {},
            levelStates: {},
            level: defaultLevel
         };
         mainTask.loadLevel(state.level, null, views);
         displayHelper.setupLevels();
         callback();
      }
      else {
         // TODO what's the desired behavior when no levels?
         mainTask.load(views, callback);
      }
   };

   task.getState = function(callback) {
      if(levels) {
         // Update state to reflect latest user interaction.
         state.levelStates[state.level] = mainTask.getStateObject();
         state.levelAnswers[state.level] = mainTask.getAnswerObject();
         callback(JSON.stringify(state));
      }
      else {
         // TODO is this the desired behavior? It is from beaver-task-1.0.
         var currentState = {};
         mainTask.getAnswer(function(displayedAnswer) {
            currentState.displayedAnswer = displayedAnswer;
            callback(JSON.stringify(currentState));
         });
      }
   };

   task.getStateObject = function() {
      return state;
   };

   task.reloadAnswer = function(strAnswer, callback) {
      var newAnswer;
      if(strAnswer) {
         newAnswer = JSON.parse(strAnswer);
      }
      else {
         newAnswer = null;
      }
      task.reloadAnswerObject(newAnswer, callback);
   };

   task.reloadAnswerObject = function(newAnswers, callback) {
      if(levels) {
         if (!newAnswers) {
            state.levelAnswers = {};
         }
         else {
            state.levelAnswers = newAnswers;
         }

         // Recreate the main task and load the relevant answer.
         var level = state.level;
         var levelAnswer = state.levelAnswers[level];
         if(levelAnswer === undefined || levelAnswer === null) {
            levelAnswer = mainTask.getDefaultAnswerObject();
            state.levelAnswers[level] = levelAnswer;
         }
         destroyTask(mainTask, function() {
            mainTask = createTask(true);
            task.displayedSubTask = mainTask;
            mainTask.loadLevel(level, state.levelStates[level]);
            mainTask.reloadAnswerObject(levelAnswer);
            if(mainTask.resetDisplay) {
               mainTask.resetDisplay();
            }
            callback();
         });
      }
      else {
         // TODO is this the desired behavior? Taken from beaver-task-1.0.
         if (!newAnswers) {
            mainTask.reloadAnswerObject(mainTask.getDefaultAnswerObject());
         } else {
            mainTask.reloadAnswerObject(JSON.parse(newAnswers));
         }
         callback();
      }
   };

   task.reloadState = function(newStateStr, callback) {
      task.reloadStateObject(JSON.parse(newStateStr), callback);
   };

   task.reloadStateObject = function(newState, callback) {
      if(levels) {
         // Recreate the task to reflect the new state.
         state = newState;
         var level = state.level;
         var levelState = state.levelStates[level];
         destroyTask(mainTask, function() {
            mainTask = createTask(true);
            task.displayedSubTask = mainTask;
            mainTask.loadLevel(level, levelState);
            mainTask.reloadAnswerObject(state.levelAnswers[level]);
            callback();
         });
      }
      else {
         // TODO is this the desired behavior? Taken from beaver-task-1.0.
         if (typeof newState.displayedAnswer !== 'undefined') {
            mainTask.reloadAnswer(newState.displayedAnswer, callback);
         }
         else {
            callback();
         }
      }
   };

   task.getDefaultStateObject = function() {
      return {
         level: defaultLevel,
         levelStates: {},
         levelAnswers: {}
      };
   };

   task.getDefaultAnswerObject = function() {
      return {};
   };

   task.getAnswer = function(callback) {
      if(levels) {
         // Update answer to reflect latest user interaction.
         state.levelAnswers[state.level] = mainTask.getAnswerObject();
         callback(JSON.stringify(state.levelAnswers));
      }
      else {
         // TODO is this desired behavior? Taken from beaver-task-1.
         var answerObj = mainTask.getAnswerObject();
         callback(JSON.stringify(answerObj));
      }
   };

   task.getAnswerObject = function() {
      return state.levelAnswers;
   };

   task.unload = function(callback) {
      var instances = [];
      for(var iLevel in gradingTasks) {
         for(var iSeed in gradingTasks[iLevel]) {
            instances.push(gradingTasks[iLevel][iSeed]);
         }
      }
      instances.push(mainTask);
      callbackLoop(instances, function(taskFor, loopCallback) {
         destroyTask(mainTask, loopCallback);
      }, function() {
         task.displayedSubTask = null;
         callback();
      });
   };

   function gradeAnswerByLevel(level, seed, levelAnswer, maxScore, callback) {
      // Create grading taskFor instance if it does not exist.
      if(!gradingTasks[level]) {
         gradingTasks[level] = {};
      }
      if(!gradingTasks[level][seed]) {
         var gradingTask = createTask(false);
         gradingTask.loadLevel(level);
         gradingTasks[level][seed] = gradingTask;
      }

      // Load answer and grade it.
      if(levelAnswer === undefined || levelAnswer === null) {
         levelAnswer = gradingTasks[level][seed].getDefaultAnswerObject();
      }
      gradingTasks[level][seed].reloadAnswerObject(levelAnswer);
      gradingTasks[level][seed].getGrade(function(grade) {
         callback({
            score: Math.round(grade.successRate * maxScore),
            message: grade.message
         });
      });
   }

   // TODO: case where gradeAnswer is called again before it calls its callback
   task.gradeAnswer = function(strAnswer, answerToken, callback, gradedLevel) {
      if(levels) {
         // TODO Can we fetch task params just once instead of every time?
         // If we can, then why do we need to index by seed in graders[level][seed]?
         platform.getTaskParams(null, null, function(taskParams) {
            if (strAnswer === '') {
               callback(taskParams.minScore, '');
               return;
            }

            var seed = taskParams.randomSeed;
            var maxScores = displayHelper.getLevelsMaxScores();

            // TODO generalize this according to list of levels?
            // What can we assume agbout maxScores?
            var gradingMaxScore = {
               easy: maxScores.easy,
               medium: maxScores.medium - maxScores.easy,
               hard: maxScores.hard - maxScores.medium
            };

            var levelAnswers = $.parseJSON(strAnswer);
            var scores = {};
            var messages = {};

            // Grade all levels. If gradedLevel is supplied, skip others.
            callbackLoop(levels, function(level, loopCallback) {
               if(gradedLevel !== null && gradedLevel !== undefined && level !== gradedLevel) {
                  loopCallback();
                  return;
               }
               gradeAnswerByLevel(level, seed, levelAnswers[level], maxScores[level], function(result) {
                  scores[level] = result.score;
                  messages[level] = result.message;
                  loopCallback();
               });
            },
            function() {
               // TODO is this correct? Taken from Arthur's level wrapper.
               if(gradedLevel === null || gradedLevel === undefined) {
                  displayHelper.sendBestScore(callback, scores, messages);
               } else {
                  callback(scores[gradedLevel], messages[gradedLevel]);
               }
            });
         });
      }
      else {
         // TODO What's the correct behavior here with no levels?
      }
   };

   if(levels) {
      // TODO is this the correct behavior?
      grader.gradeTask = task.gradeAnswer;
   }
}

$('document').ready(function() {
   platform.initWithTask(window.task);
});
<|endoftext|>


<commit_before>import color from "color";

import { Platform, Dimensions, PixelRatio } from "react-native";

const deviceHeight = Dimensions.get("window").height;
const deviceWidth = Dimensions.get("window").width;
const platform = Platform.OS;
const platformStyle = undefined;
const isIphoneX = platform === "ios" && deviceHeight === 812 && deviceWidth === 375;

export default {
  platformStyle,
  platform,
  // AndroidRipple
  androidRipple: true,
  androidRippleColor: "rgba(256, 256, 256, 0.3)",
  androidRippleColorDark: "rgba(0, 0, 0, 0.15)",

  // Badge
  badgeBg: "#ED1727",
  badgeColor: "#fff",
  // New Variable
  badgePadding: platform === "ios" ? 3 : 0,

  // Button
  btnFontFamily: platform === "ios" ? "System" : "Roboto_medium",
  btnDisabledBg: "#b5b5b5",

  //Android
  btnUppercaseAndroidText: true,

  // CheckBox
  CheckboxRadius: platform === "ios" ? 13 : 0,
  CheckboxBorderWidth: platform === "ios" ? 1 : 2,
  CheckboxPaddingLeft: platform === "ios" ? 4 : 2,
  CheckboxPaddingBottom: platform === "ios" ? 0 : 5,
  CheckboxIconSize: platform === "ios" ? 21 : 14,
  CheckboxIconMarginTop: platform === "ios" ? undefined : 1,
  CheckboxFontSize: platform === "ios" ? 23 / 0.9 : 18,
  DefaultFontSize: 17,
  checkboxBgColor: "#039BE5",
  checkboxSize: 20,
  checkboxTickColor: "#fff",

  // Segment
  segmentBackgroundColor: "#3F51B5",
  segmentActiveBackgroundColor: "#fff",
  segmentTextColor: "#fff",
  segmentActiveTextColor: "#3F51B5",
  segmentBorderColor: "#fff",
  segmentBorderColorMain: "#3F51B5",

  // New Variable
  get defaultTextColor() {
    return this.textColor;
  },

  get btnPrimaryBg() {
    return this.brandPrimary;
  },
  get btnPrimaryColor() {
    return this.inverseTextColor;
  },
  get btnInfoBg() {
    return this.brandInfo;
  },
  get btnInfoColor() {
    return this.inverseTextColor;
  },
  get btnSuccessBg() {
    return this.brandSuccess;
  },
  get btnSuccessColor() {
    return this.inverseTextColor;
  },
  get btnDangerBg() {
    return this.brandDanger;
  },
  get btnDangerColor() {
    return this.inverseTextColor;
  },
  get btnWarningBg() {
    return this.brandWarning;
  },
  get btnWarningColor() {
    return this.inverseTextColor;
  },
  get btnTextSize() {
    return platform === "ios" ? this.fontSizeBase * 1.1 : this.fontSizeBase - 1;
  },
  get btnTextSizeLarge() {
    return this.fontSizeBase * 1.5;
  },
  get btnTextSizeSmall() {
    return this.fontSizeBase * 0.8;
  },
  get borderRadiusLarge() {
    return this.fontSizeBase * 3.8;
  },

  buttonPadding: 6,

  get iconSizeLarge() {
    return this.iconFontSize * 1.5;
  },
  get iconSizeSmall() {
    return this.iconFontSize * 0.6;
  },

  // Card
  cardDefaultBg: "#fff",

  // Color
  brandPrimary: "#2874F0",
  brandInfo: "#62B1F6",
  brandSuccess: "#5cb85c",
  brandDanger: "#d9534f",
  brandWarning: "#f0ad4e",
  brandDark: "#000",
  brandLight: "#f4f4f4",

  // Font
  fontFamily: platform === "ios" ? "System" : "Roboto",
  fontSizeBase: 15,

  get fontSizeH1() {
    return this.fontSizeBase * 1.8;
  },
  get fontSizeH2() {
    return this.fontSizeBase * 1.6;
  },
  get fontSizeH3() {
    return this.fontSizeBase * 1.4;
  },

  // Footer
  footerHeight: isIphoneX ? 89 : 55,
  footerDefaultBg: "#2874F0",
  footerPaddingBottom: isIphoneX ? 34 : 0,

  // FooterTab
  tabBarTextColor: "#8bb3f4",
  tabBarTextSize: platform === "ios" ? 14 : 11,
  activeTab: platform === "ios" ? "#007aff" : "#fff",
  sTabBarActiveTextColor: "#007aff",
  tabBarActiveTextColor: "#fff",
  tabActiveBgColor: platform === "ios" ? "#1569f4" : undefined,

  // Tab
  tabDefaultBg: "#2874F0",
  topTabBarTextColor: "#b3c7f9",
  topTabBarActiveTextColor: "#fff",
  topTabBarBorderColor: "#fff",
  topTabBarActiveBorderColor: "#fff",

  // Header
  toolbarBtnColor: "#fff",
  toolbarDefaultBg: "#2874F0",
  toolbarHeight: platform === "ios" ? (isIphoneX ? 88 : 64) : 56,
  toolbarSearchIconSize: platform === "ios" ? 20 : 23,
  toolbarInputColor: platform === "ios" ? "#CECDD2" : "#fff",
  searchBarHeight: platform === "ios" ? 30 : 40,
  searchBarInputHeight: platform === "ios" ? 30 : 50,
  toolbarBtnTextColor: "#fff",
  iosStatusbar: "light-content",
  toolbarDefaultBorder: "#2874F0",
  get statusBarColor() {
    return color(this.toolbarDefaultBg)
      .darken(0.2)
      .hex();
  },

  // Icon
  iconFamily: "Ionicons",
  iconFontSize: platform === "ios" ? 30 : 28,
  iconHeaderSize: platform === "ios" ? 33 : 24,

  // InputGroup
  inputFontSize: 17,
  inputBorderColor: "#D9D5DC",
  inputSuccessBorderColor: "#2b8339",
  inputErrorBorderColor: "#ed2f2f",

  get inputColor() {
    return this.textColor;
  },
  get inputColorPlaceholder() {
    return "#575757";
  },

  inputHeightBase: 50,

  // Line Height
  btnLineHeight: 19,
  lineHeightH1: 32,
  lineHeightH2: 27,
  lineHeightH3: 22,
  lineHeight: platform === "ios" ? 20 : 24,

  // List
  listBg: "#fff",
  listBorderColor: "#c9c9c9",
  listDividerBg: "#f4f4f4",
  listBtnUnderlayColor: "#DDD",

  // Card
  cardBorderColor: "#ccc",

  // Changed Variable
  listItemPadding: platform === "ios" ? 10 : 12,

  listNoteColor: "#808080",
  listNoteSize: 13,

  // Progress Bar
  defaultProgressColor: "#E4202D",
  inverseProgressColor: "#1A191B",

  // Radio Button
  radioBtnSize: platform === "ios" ? 25 : 23,
  radioSelectedColorAndroid: "#5067FF",

  // New Variable
  radioBtnLineHeight: platform === "ios" ? 29 : 24,

  radioColor: this.brandPrimary,

  get radioSelectedColor() {
    return color(this.radioColor)
      .darken(0.2)
      .hex();
  },

  // Spinner
  defaultSpinnerColor: "#45D56E",
  inverseSpinnerColor: "#1A191B",

  // Tabs
  tabBgColor: "#F8F8F8",
  tabFontSize: 15,

  // Text
  textColor: "#000",
  inverseTextColor: "#fff",
  noteFontSize: 14,

  // Title
  titleFontfamily: platform === "ios" ? "System" : "Roboto_medium",
  titleFontSize: platform === "ios" ? 17 : 19,
  subTitleFontSize: platform === "ios" ? 12 : 14,
  subtitleColor: "#FFF",

  // New Variable
  titleFontColor: "#FFF",

  // Other
  borderRadiusBase: platform === "ios" ? 5 : 2,
  borderWidth: 1 / PixelRatio.getPixelSizeForLayoutSize(1),
  contentPadding: 10,

  get darkenHeader() {
    return color(this.tabBgColor)
      .darken(0.03)
      .hex();
  },

  dropdownLinkColor: "#414142",
  inputLineHeight: 24,
  deviceWidth,
  deviceHeight,
  isIphoneX,

  // New Variable
  inputGroupRoundedBorderRadius: 30,
};
<commit_msg>Modified variable values of commonColor.js<commit_after>import color from "color";

import { Platform, Dimensions, PixelRatio } from "react-native";

const deviceHeight = Dimensions.get("window").height;
const deviceWidth = Dimensions.get("window").width;
const platform = Platform.OS;
const platformStyle = undefined;
const isIphoneX = platform === "ios" && deviceHeight === 812 && deviceWidth === 375;

export default {
  platformStyle,
  platform,
  // AndroidRipple
  androidRipple: true,
  androidRippleColor: "rgba(256, 256, 256, 0.3)",
  androidRippleColorDark: "rgba(0, 0, 0, 0.15)",

  // Badge
  badgeBg: "#ED1727",
  badgeColor: "#fff",
  // New Variable
  badgePadding: platform === "ios" ? 3 : 0,

  // Button
  btnFontFamily: platform === "ios" ? "System" : "Roboto_medium",
  btnDisabledBg: "#b5b5b5",

  //Android
  btnUppercaseAndroidText: true,

  // CheckBox
  CheckboxRadius: platform === "ios" ? 13 : 0,
  CheckboxBorderWidth: platform === "ios" ? 1 : 2,
  CheckboxPaddingLeft: platform === "ios" ? 4 : 2,
  CheckboxPaddingBottom: platform === "ios" ? 0 : 5,
  CheckboxIconSize: platform === "ios" ? 21 : 14,
  CheckboxIconMarginTop: platform === "ios" ? undefined : 1,
  CheckboxFontSize: platform === "ios" ? 23 / 0.9 : 18,
  DefaultFontSize: 17,
  checkboxBgColor: "#039BE5",
  checkboxSize: 20,
  checkboxTickColor: "#fff",

  // Segment
  segmentBackgroundColor: platform === "ios" ? "#F8F8F8" : "#3F51B5",
  segmentActiveBackgroundColor: platform === "ios" ? "#007aff" : "#fff",
  segmentTextColor: platform === "ios" ? "#007aff" : "#fff",
  segmentActiveTextColor: platform === "ios" ? "#fff" : "#3F51B5",
  segmentBorderColor: platform === "ios" ? "#007aff" : "#fff",
  segmentBorderColorMain: platform === "ios" ? "#a7a6ab" : "#3F51B5",

  // New Variable
  get defaultTextColor() {
    return this.textColor;
  },

  get btnPrimaryBg() {
    return this.brandPrimary;
  },
  get btnPrimaryColor() {
    return this.inverseTextColor;
  },
  get btnInfoBg() {
    return this.brandInfo;
  },
  get btnInfoColor() {
    return this.inverseTextColor;
  },
  get btnSuccessBg() {
    return this.brandSuccess;
  },
  get btnSuccessColor() {
    return this.inverseTextColor;
  },
  get btnDangerBg() {
    return this.brandDanger;
  },
  get btnDangerColor() {
    return this.inverseTextColor;
  },
  get btnWarningBg() {
    return this.brandWarning;
  },
  get btnWarningColor() {
    return this.inverseTextColor;
  },
  get btnTextSize() {
    return platform === "ios" ? this.fontSizeBase * 1.1 : this.fontSizeBase - 1;
  },
  get btnTextSizeLarge() {
    return this.fontSizeBase * 1.5;
  },
  get btnTextSizeSmall() {
    return this.fontSizeBase * 0.8;
  },
  get borderRadiusLarge() {
    return this.fontSizeBase * 3.8;
  },

  buttonPadding: 6,

  get iconSizeLarge() {
    return this.iconFontSize * 1.5;
  },
  get iconSizeSmall() {
    return this.iconFontSize * 0.6;
  },

  // Card
  cardDefaultBg: "#fff",

  // Color
  brandPrimary: platform === "ios" ? "#007aff" : "#3F51B5",
  brandInfo: "#62B1F6",
  brandSuccess: "#5cb85c",
  brandDanger: "#d9534f",
  brandWarning: "#f0ad4e",
  brandDark: "#000",
  brandLight: "#f4f4f4",

  // Font
  fontFamily: platform === "ios" ? "System" : "Roboto",
  fontSizeBase: 15,

  get fontSizeH1() {
    return this.fontSizeBase * 1.8;
  },
  get fontSizeH2() {
    return this.fontSizeBase * 1.6;
  },
  get fontSizeH3() {
    return this.fontSizeBase * 1.4;
  },

  // Footer
  footerHeight: isIphoneX ? 89 : 55,
  footerDefaultBg: platform === "ios" ? "#F8F8F8" : "#3F51B5",
  footerPaddingBottom: isIphoneX ? 34 : 0,

  // FooterTab
  tabBarTextColor: platform === "ios" ? "#737373" : "#bfc6ea",
  tabBarTextSize: platform === "ios" ? 14 : 11,
  activeTab: platform === "ios" ? "#007aff" : "#fff",
  sTabBarActiveTextColor: "#007aff",
  tabBarActiveTextColor: platform === "ios" ? "#2874F0" : "#fff",
  tabActiveBgColor: platform === "ios" ? "#cde1f9" : "#3F51B5",

  // Tab
  tabDefaultBg: platform === "ios" ? "#F8F8F8" : "#3F51B5",
  topTabBarTextColor: platform === "ios" ? "#6b6b6b" : "#b3c7f9",
  topTabBarActiveTextColor: platform === "ios" ? "#007aff" : "#fff",
  topTabBarBorderColor: platform === "ios" ? "#a7a6ab" : "#fff",
  topTabBarActiveBorderColor: platform === "ios" ? "#007aff" : "#fff",

  // Header
  toolbarBtnColor: platform === "ios" ? "#007aff" : "#fff",
  toolbarDefaultBg: platform === "ios" ? "#F8F8F8" : "#3F51B5",
  toolbarHeight: platform === "ios" ? (isIphoneX ? 88 : 64) : 56,
  toolbarSearchIconSize: platform === "ios" ? 20 : 23,
  toolbarInputColor: platform === "ios" ? "#CECDD2" : "#fff",
  searchBarHeight: platform === "ios" ? 30 : 40,
  searchBarInputHeight: platform === "ios" ? 30 : 50,
  toolbarBtnTextColor: platform === "ios" ? "#000" : "#fff",
  iosStatusbar: "dark-content",
  toolbarDefaultBorder: platform === "ios" ? "#a7a6ab" : "#3F51B5",
  get statusBarColor() {
    return color(this.toolbarDefaultBg)
      .darken(0.2)
      .hex();
  },

  // Icon
  iconFamily: "Ionicons",
  iconFontSize: platform === "ios" ? 30 : 28,
  iconHeaderSize: platform === "ios" ? 33 : 24,

  // InputGroup
  inputFontSize: 17,
  inputBorderColor: "#D9D5DC",
  inputSuccessBorderColor: "#2b8339",
  inputErrorBorderColor: "#ed2f2f",

  get inputColor() {
    return this.textColor;
  },
  get inputColorPlaceholder() {
    return "#575757";
  },

  inputHeightBase: 50,

  // Line Height
  btnLineHeight: 19,
  lineHeightH1: 32,
  lineHeightH2: 27,
  lineHeightH3: 22,
  lineHeight: platform === "ios" ? 20 : 24,

  // List
  listBg: "#fff",
  listBorderColor: "#c9c9c9",
  listDividerBg: "#f4f4f4",
  listBtnUnderlayColor: "#DDD",

  // Card
  cardBorderColor: "#ccc",

  // Changed Variable
  listItemPadding: platform === "ios" ? 10 : 12,

  listNoteColor: "#808080",
  listNoteSize: 13,

  // Progress Bar
  defaultProgressColor: "#E4202D",
  inverseProgressColor: "#1A191B",

  // Radio Button
  radioBtnSize: platform === "ios" ? 25 : 23,
  radioSelectedColorAndroid: "#5067FF",

  // New Variable
  radioBtnLineHeight: platform === "ios" ? 29 : 24,

  radioColor: this.brandPrimary,

  get radioSelectedColor() {
    return color(this.radioColor)
      .darken(0.2)
      .hex();
  },

  // Spinner
  defaultSpinnerColor: "#45D56E",
  inverseSpinnerColor: "#1A191B",

  // Tabs
  tabBgColor: "#F8F8F8",
  tabFontSize: 15,

  // Text
  textColor: "#000",
  inverseTextColor: "#fff",
  noteFontSize: 14,

  // Title
  titleFontfamily: platform === "ios" ? "System" : "Roboto_medium",
  titleFontSize: platform === "ios" ? 17 : 19,
  subTitleFontSize: platform === "ios" ? 12 : 14,
  subtitleColor: platform === "ios" ? "#000" : "#fff",

  // New Variable
  titleFontColor: platform === "ios" ? "#000" : "#fff",

  // Other
  borderRadiusBase: platform === "ios" ? 5 : 2,
  borderWidth: 1 / PixelRatio.getPixelSizeForLayoutSize(1),
  contentPadding: 10,

  get darkenHeader() {
    return color(this.tabBgColor)
      .darken(0.03)
      .hex();
  },

  dropdownLinkColor: "#414142",
  inputLineHeight: 24,
  deviceWidth,
  deviceHeight,
  isIphoneX,

  // New Variable
  inputGroupRoundedBorderRadius: 30,
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import { isEqual } from 'lodash';
import { connectStyle, StyleProvider } from 'native-base-shoutem-theme';
import mapPropsToStyleNames from '../../utils/mapPropsToStyleNames';
import variable from './../../theme/variables/platform';
import { TabHeading } from '../TabHeading';
import { Text } from '../Text';
import { TabContainer } from '../TabContainer';
import { ViewPropTypes } from '../../utils';
const Button = require('./Button');
const ReactNative = require('react-native');
const {
  View,
  Animated,
  StyleSheet,
  ScrollView,
  Platform,
  Dimensions
} = ReactNative;

const WINDOW_WIDTH = Dimensions.get('window').width;

const ScrollableTabBar = createReactClass({
  propTypes: {
    goToPage: PropTypes.func,
    activeTab: PropTypes.number,
    tabs: PropTypes.array,
    backgroundColor: PropTypes.string,
    activeTextColor: PropTypes.string,
    inactiveTextColor: PropTypes.string,
    scrollOffset: PropTypes.number,
    style: ViewPropTypes.style,
    tabStyle: ViewPropTypes.style,
    tabsContainerStyle: ViewPropTypes.style,
    renderTab: PropTypes.func,
    underlineStyle: ViewPropTypes.style,
    onScroll: PropTypes.func
  },
  contextTypes: {
    theme: PropTypes.object
  },

  getDefaultProps() {
    return {
      scrollOffset: 52,
      activeTextColor: 'navy',
      inactiveTextColor: 'black',
      backgroundColor: variable.tabDefaultBg,
      style: {},
      tabStyle: {},
      tabsContainerStyle: {},
      underlineStyle: {},
      tabFontSize: variable.tabFontSize
    };
  },

  getInitialState() {
    this._tabsMeasurements = [];
    return {
      _leftTabUnderline: new Animated.Value(0),
      _widthTabUnderline: new Animated.Value(0),
      _containerWidth: null
    };
  },

  componentDidMount() {
    this.props.scrollValue.addListener(this.updateView);
  },

  updateView(offset) {
    const position = Math.floor(offset.value);
    const pageOffset = offset.value % 1;
    const tabCount = this.props.tabs.length;
    const lastTabPosition = tabCount - 1;

    if (tabCount === 0 || offset.value < 0 || offset.value > lastTabPosition) {
      return;
    }

    if (
      this.necessarilyMeasurementsCompleted(
        position,
        position === lastTabPosition
      )
    ) {
      this.updateTabPanel(position, pageOffset);
      this.updateTabUnderline(position, pageOffset, tabCount);
    }
  },

  necessarilyMeasurementsCompleted(position, isLastTab) {
    return (
      this._tabsMeasurements[position] &&
      (isLastTab || this._tabsMeasurements[position + 1]) &&
      this._tabContainerMeasurements &&
      this._containerMeasurements
    );
  },

  updateTabPanel(position, pageOffset) {
    const containerWidth = this._containerMeasurements.width;
    const tabWidth = this._tabsMeasurements[position].width;
    const nextTabMeasurements = this._tabsMeasurements[position + 1];
    const nextTabWidth =
      (nextTabMeasurements && nextTabMeasurements.width) || 0;
    const tabOffset = this._tabsMeasurements[position].left;
    const absolutePageOffset = pageOffset * tabWidth;
    let newScrollX = tabOffset + absolutePageOffset;

    // center tab and smooth tab change (for when tabWidth changes a lot between two tabs)
    newScrollX -=
      (containerWidth -
        (1 - pageOffset) * tabWidth -
        pageOffset * nextTabWidth) /
      2;
    newScrollX = newScrollX >= 0 ? newScrollX : 0;

    if (Platform.OS === 'android') {
      this._scrollView.scrollTo({ x: newScrollX, y: 0, animated: false });
    } else {
      const rightBoundScroll =
        this._tabContainerMeasurements.width -
        this._containerMeasurements.width;
      newScrollX =
        newScrollX > rightBoundScroll ? rightBoundScroll : newScrollX;
      this._scrollView.scrollTo({ x: newScrollX, y: 0, animated: false });
    }
  },

  updateTabUnderline(position, pageOffset, tabCount) {
    const lineLeft = this._tabsMeasurements[position].left;
    const lineRight = this._tabsMeasurements[position].right;

    if (position < tabCount - 1) {
      const nextTabLeft = this._tabsMeasurements[position + 1].left;
      const nextTabRight = this._tabsMeasurements[position + 1].right;

      const newLineLeft =
        pageOffset * nextTabLeft + (1 - pageOffset) * lineLeft;
      const newLineRight =
        pageOffset * nextTabRight + (1 - pageOffset) * lineRight;

      this.state._leftTabUnderline.setValue(newLineLeft);
      this.state._widthTabUnderline.setValue(newLineRight - newLineLeft);
    } else {
      this.state._leftTabUnderline.setValue(lineLeft);
      this.state._widthTabUnderline.setValue(lineRight - lineLeft);
    }
  },

  renderTab(
    name,
    page,
    isTabActive,
    onPressHandler,
    onLayoutHandler,
    tabStyle,
    activeTabStyle,
    textStyle,
    activeTextStyle,
    tabHeaderStyle,
    tabFontSize
  ) {
    const headerContent =
      typeof name !== 'string' ? name.props.children : undefined;
    const { activeTextColor, inactiveTextColor } = this.props;
    const textColor = isTabActive ? activeTextColor : inactiveTextColor;
    const fontWeight = isTabActive ? 'bold' : 'normal';

    if (typeof name === 'string') {
      return (
        <Button
          key={`${name}_${page}`}
          onPress={() => onPressHandler(page)}
          onLayout={onLayoutHandler}
        >
          <TabHeading
            scrollable
            style={isTabActive ? activeTabStyle : tabStyle}
            active={isTabActive}
          >
            <Text
              style={[
                isTabActive ? activeTextStyle : textStyle,
                { fontSize: tabFontSize }
              ]}
            >
              {name}
            </Text>
          </TabHeading>
        </Button>
      );
    }
    return (
      <Button
        key={`${name}_${page}`}
        onPress={() => onPressHandler(page)}
        onLayout={onLayoutHandler}
      >
        <TabHeading scrollable style={tabHeaderStyle} active={isTabActive}>
          {headerContent}
        </TabHeading>
      </Button>
    );

  },

  measureTab(page, event) {
    const { x, width, height } = event.nativeEvent.layout;
    this._tabsMeasurements[page] = { left: x, right: x + width, width, height };
    this.updateView({ value: this.props.scrollValue._value });
  },

  render() {
    const variables = this.context.theme
      ? this.context.theme['@@shoutem.theme/themeStyle'].variables
      : variable;
    const tabUnderlineStyle = {
      position: 'absolute',
      height: 4,
      backgroundColor: variables.topTabBarActiveBorderColor,
      bottom: 0
    };

    const dynamicTabUnderline = {
      left: this.state._leftTabUnderline,
      width: this.state._widthTabUnderline
    };

    return (
      <View
        style={[
          styles.container,
          { backgroundColor: this.props.backgroundColor },
          this.props.style
        ]}
        onLayout={this.onContainerLayout}
      >
        <ScrollView
          automaticallyAdjustContentInsets={false}
          ref={scrollView => {
            this._scrollView = scrollView;
          }}
          horizontal
          showsHorizontalScrollIndicator={false}
          showsVerticalScrollIndicator={false}
          directionalLockEnabled
          onScroll={this.props.onScroll}
          bounces={false}
          scrollsToTop={false}
        >
          <View
            style={[
              styles.tabs,
              { width: this.state._containerWidth },
              this.props.tabsContainerStyle
            ]}
            ref={'tabContainer'}
            onLayout={this.onTabContainerLayout}
          >
            {this.props.tabs.map((name, page) => {
              const isTabActive = this.props.activeTab === page;
              const renderTab = this.props.renderTab || this.renderTab;
              return renderTab(
                name,
                page,
                isTabActive,
                this.props.goToPage,
                this.measureTab.bind(this, page),
                this.props.tabStyle[page],
                this.props.activeTabStyle[page],
                this.props.textStyle[page],
                this.props.activeTextStyle[page],
                this.props.tabHeaderStyle[page],
                variables.tabFontSize
              );
            })}
            <Animated.View
              style={[
                tabUnderlineStyle,
                dynamicTabUnderline,
                this.props.underlineStyle
              ]}
            />
          </View>
        </ScrollView>
      </View>
    );
  },

  componentDidUpdate(nextProps) {
    // If the tabs change, force the width of the tabs container to be recalculated
    if (
      !isEqual(this.props.tabs, nextProps.tabs) &&
      this.state._containerWidth
    ) {
      this.setState({ _containerWidth: null });
    }
  },

  onTabContainerLayout(e) {
    this._tabContainerMeasurements = e.nativeEvent.layout;
    let width = this._tabContainerMeasurements.width;
    if (width < WINDOW_WIDTH) {
      width = WINDOW_WIDTH;
    }
    this.setState({ _containerWidth: width });
    this.updateView({ value: this.props.scrollValue._value });
  },

  onContainerLayout(e) {
    this._containerMeasurements = e.nativeEvent.layout;
    this.updateView({ value: this.props.scrollValue._value });
  }
});

// module.exports = ScrollableTabBar;
const StyledTab = connectStyle(
  'NativeBase.ScrollableTab',
  {},
  mapPropsToStyleNames
)(ScrollableTabBar);
export { StyledTab as ScrollableTab };
const styles = StyleSheet.create({
  tab: {
    height: 49,
    alignItems: 'center',
    justifyContent: 'center',
    paddingLeft: 20,
    paddingRight: 20
  },
  container: {
    height: 50,
    borderWidth: 1,
    borderTopWidth: 0,
    borderLeftWidth: 0,
    borderRightWidth: 0,
    borderColor: '#ccc'
  },
  tabs: {
    flexDirection: 'row',
    justifyContent: 'space-around'
  }
});
<commit_msg>fix(): removes didUpdate setState on Tabs<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import createReactClass from 'create-react-class';
import { isEqual } from 'lodash';
import { connectStyle, StyleProvider } from 'native-base-shoutem-theme';
import mapPropsToStyleNames from '../../utils/mapPropsToStyleNames';
import variable from './../../theme/variables/platform';
import { TabHeading } from '../TabHeading';
import { Text } from '../Text';
import { TabContainer } from '../TabContainer';
import { ViewPropTypes } from '../../utils';
const Button = require('./Button');
const ReactNative = require('react-native');
const {
  View,
  Animated,
  StyleSheet,
  ScrollView,
  Platform,
  Dimensions
} = ReactNative;

const WINDOW_WIDTH = Dimensions.get('window').width;

const ScrollableTabBar = createReactClass({
  propTypes: {
    goToPage: PropTypes.func,
    activeTab: PropTypes.number,
    tabs: PropTypes.array,
    backgroundColor: PropTypes.string,
    activeTextColor: PropTypes.string,
    inactiveTextColor: PropTypes.string,
    scrollOffset: PropTypes.number,
    style: ViewPropTypes.style,
    tabStyle: ViewPropTypes.style,
    tabsContainerStyle: ViewPropTypes.style,
    renderTab: PropTypes.func,
    underlineStyle: ViewPropTypes.style,
    onScroll: PropTypes.func
  },
  contextTypes: {
    theme: PropTypes.object
  },

  getDefaultProps() {
    return {
      scrollOffset: 52,
      activeTextColor: 'navy',
      inactiveTextColor: 'black',
      backgroundColor: variable.tabDefaultBg,
      style: {},
      tabStyle: {},
      tabsContainerStyle: {},
      underlineStyle: {},
      tabFontSize: variable.tabFontSize
    };
  },

  getInitialState() {
    this._tabsMeasurements = [];
    return {
      _leftTabUnderline: new Animated.Value(0),
      _widthTabUnderline: new Animated.Value(0),
      _containerWidth: null
    };
  },

  componentDidMount() {
    this.props.scrollValue.addListener(this.updateView);
  },

  updateView(offset) {
    const position = Math.floor(offset.value);
    const pageOffset = offset.value % 1;
    const tabCount = this.props.tabs.length;
    const lastTabPosition = tabCount - 1;

    if (tabCount === 0 || offset.value < 0 || offset.value > lastTabPosition) {
      return;
    }

    if (
      this.necessarilyMeasurementsCompleted(
        position,
        position === lastTabPosition
      )
    ) {
      this.updateTabPanel(position, pageOffset);
      this.updateTabUnderline(position, pageOffset, tabCount);
    }
  },

  necessarilyMeasurementsCompleted(position, isLastTab) {
    return (
      this._tabsMeasurements[position] &&
      (isLastTab || this._tabsMeasurements[position + 1]) &&
      this._tabContainerMeasurements &&
      this._containerMeasurements
    );
  },

  updateTabPanel(position, pageOffset) {
    const containerWidth = this._containerMeasurements.width;
    const tabWidth = this._tabsMeasurements[position].width;
    const nextTabMeasurements = this._tabsMeasurements[position + 1];
    const nextTabWidth =
      (nextTabMeasurements && nextTabMeasurements.width) || 0;
    const tabOffset = this._tabsMeasurements[position].left;
    const absolutePageOffset = pageOffset * tabWidth;
    let newScrollX = tabOffset + absolutePageOffset;

    // center tab and smooth tab change (for when tabWidth changes a lot between two tabs)
    newScrollX -=
      (containerWidth -
        (1 - pageOffset) * tabWidth -
        pageOffset * nextTabWidth) /
      2;
    newScrollX = newScrollX >= 0 ? newScrollX : 0;

    if (Platform.OS === 'android') {
      this._scrollView.scrollTo({ x: newScrollX, y: 0, animated: false });
    } else {
      const rightBoundScroll =
        this._tabContainerMeasurements.width -
        this._containerMeasurements.width;
      newScrollX =
        newScrollX > rightBoundScroll ? rightBoundScroll : newScrollX;
      this._scrollView.scrollTo({ x: newScrollX, y: 0, animated: false });
    }
  },

  updateTabUnderline(position, pageOffset, tabCount) {
    const lineLeft = this._tabsMeasurements[position].left;
    const lineRight = this._tabsMeasurements[position].right;

    if (position < tabCount - 1) {
      const nextTabLeft = this._tabsMeasurements[position + 1].left;
      const nextTabRight = this._tabsMeasurements[position + 1].right;

      const newLineLeft =
        pageOffset * nextTabLeft + (1 - pageOffset) * lineLeft;
      const newLineRight =
        pageOffset * nextTabRight + (1 - pageOffset) * lineRight;

      this.state._leftTabUnderline.setValue(newLineLeft);
      this.state._widthTabUnderline.setValue(newLineRight - newLineLeft);
    } else {
      this.state._leftTabUnderline.setValue(lineLeft);
      this.state._widthTabUnderline.setValue(lineRight - lineLeft);
    }
  },

  renderTab(
    name,
    page,
    isTabActive,
    onPressHandler,
    onLayoutHandler,
    tabStyle,
    activeTabStyle,
    textStyle,
    activeTextStyle,
    tabHeaderStyle,
    tabFontSize
  ) {
    const headerContent =
      typeof name !== 'string' ? name.props.children : undefined;
    const { activeTextColor, inactiveTextColor } = this.props;
    const textColor = isTabActive ? activeTextColor : inactiveTextColor;
    const fontWeight = isTabActive ? 'bold' : 'normal';

    if (typeof name === 'string') {
      return (
        <Button
          key={`${name}_${page}`}
          onPress={() => onPressHandler(page)}
          onLayout={onLayoutHandler}
        >
          <TabHeading
            scrollable
            style={isTabActive ? activeTabStyle : tabStyle}
            active={isTabActive}
          >
            <Text
              style={[
                isTabActive ? activeTextStyle : textStyle,
                { fontSize: tabFontSize }
              ]}
            >
              {name}
            </Text>
          </TabHeading>
        </Button>
      );
    }
    return (
      <Button
        key={`${name}_${page}`}
        onPress={() => onPressHandler(page)}
        onLayout={onLayoutHandler}
      >
        <TabHeading scrollable style={tabHeaderStyle} active={isTabActive}>
          {headerContent}
        </TabHeading>
      </Button>
    );

  },

  measureTab(page, event) {
    const { x, width, height } = event.nativeEvent.layout;
    this._tabsMeasurements[page] = { left: x, right: x + width, width, height };
    this.updateView({ value: this.props.scrollValue._value });
  },

  render() {
    const variables = this.context.theme
      ? this.context.theme['@@shoutem.theme/themeStyle'].variables
      : variable;
    const tabUnderlineStyle = {
      position: 'absolute',
      height: 4,
      backgroundColor: variables.topTabBarActiveBorderColor,
      bottom: 0
    };

    const dynamicTabUnderline = {
      left: this.state._leftTabUnderline,
      width: this.state._widthTabUnderline
    };

    return (
      <View
        style={[
          styles.container,
          { backgroundColor: this.props.backgroundColor },
          this.props.style
        ]}
        onLayout={this.onContainerLayout}
      >
        <ScrollView
          automaticallyAdjustContentInsets={false}
          ref={scrollView => {
            this._scrollView = scrollView;
          }}
          horizontal
          showsHorizontalScrollIndicator={false}
          showsVerticalScrollIndicator={false}
          directionalLockEnabled
          onScroll={this.props.onScroll}
          bounces={false}
          scrollsToTop={false}
        >
          <View
            style={[
              styles.tabs,
              { width: this.state._containerWidth },
              this.props.tabsContainerStyle
            ]}
            ref={'tabContainer'}
            onLayout={this.onTabContainerLayout}
          >
            {this.props.tabs.map((name, page) => {
              const isTabActive = this.props.activeTab === page;
              const renderTab = this.props.renderTab || this.renderTab;
              return renderTab(
                name,
                page,
                isTabActive,
                this.props.goToPage,
                this.measureTab.bind(this, page),
                this.props.tabStyle[page],
                this.props.activeTabStyle[page],
                this.props.textStyle[page],
                this.props.activeTextStyle[page],
                this.props.tabHeaderStyle[page],
                variables.tabFontSize
              );
            })}
            <Animated.View
              style={[
                tabUnderlineStyle,
                dynamicTabUnderline,
                this.props.underlineStyle
              ]}
            />
          </View>
        </ScrollView>
      </View>
    );
  },

  UNSAFE_componentWillReceiveProps(nextProps) {
    // If the tabs change, force the width of the tabs container to be recalculated
    if (
      !isEqual(this.props.tabs, nextProps.tabs) &&
      this.state._containerWidth
    ) {
      this.setState({ _containerWidth: null });
    }
  },

  onTabContainerLayout(e) {
    this._tabContainerMeasurements = e.nativeEvent.layout;
    let width = this._tabContainerMeasurements.width;
    if (width < WINDOW_WIDTH) {
      width = WINDOW_WIDTH;
    }
    this.setState({ _containerWidth: width });
    this.updateView({ value: this.props.scrollValue._value });
  },

  onContainerLayout(e) {
    this._containerMeasurements = e.nativeEvent.layout;
    this.updateView({ value: this.props.scrollValue._value });
  }
});

// module.exports = ScrollableTabBar;
const StyledTab = connectStyle(
  'NativeBase.ScrollableTab',
  {},
  mapPropsToStyleNames
)(ScrollableTabBar);
export { StyledTab as ScrollableTab };
const styles = StyleSheet.create({
  tab: {
    height: 49,
    alignItems: 'center',
    justifyContent: 'center',
    paddingLeft: 20,
    paddingRight: 20
  },
  container: {
    height: 50,
    borderWidth: 1,
    borderTopWidth: 0,
    borderLeftWidth: 0,
    borderRightWidth: 0,
    borderColor: '#ccc'
  },
  tabs: {
    flexDirection: 'row',
    justifyContent: 'space-around'
  }
});
<|endoftext|>


<commit_before>/*! Pickyfill - Offline caching for picturefill responsive image polyfill. Author: Rich Trott | Copyright: Regents of University of California, 2012 | License: MIT */

(function( w ) {
    "use strict";

    var localStorage = w.localStorage,
        applicationCache = w.applicationCache,
        image,
        imageSrc,
        dataUri,
        pf_index_string,
        pf_index,
        canvasTest = document.createElement('canvas');

    // Don't run any of this stuff if application cache doesn't exist or isn't being used,
    //     or localStorage or canvas are not available.
    if ( (! applicationCache) || (applicationCache.status === applicationCache.UNCACHED) ||
        (! localStorage) || (!(canvasTest.getContext && canvasTest.getContext('2d'))) ) {
            return;
    }

    pf_index_string = localStorage.getItem('pf_index') || '{}';
    pf_index = JSON.parse(pf_index_string);

    // We'll use this to clear the pickyfill cache when appcache updates.
    var clearCache = function () {
        localStorage.removeItem('pf_index');
        for (var prop in pf_index) {
            localStorage.removeItem(prop);
        }
    };

    // Unfortunately, reloading is the most reliable way to get stuff into the
    //  pickyfill cache. If you wait for the user to reload, they may be offline
    //  at that time. If we just had an updateready event, chances are very good
    //  that they are still online. Another possibility is to just try to reload
    //  the images that are currently shown, but there's no guarantee that those
    //  images are in the new page or that the current page isn't missing important
    //  images that will display in the new page and need to be cached.
    var refreshCache = function () {
        clearCache();
        w.location.reload();
    };

    // If appcache updates, refresh the pickyfill cache to get new items.
    // If appcache is obsolete, clear the pickyfill cache.
    // Appcache == IE10 or later == no need to worry about attachEvent (IE8 and earlier)
    // Anything that has appcache is going to have addEventListener.
    applicationCache.addEventListener('updateready', refreshCache, false);
    applicationCache.addEventListener('obsolete', clearCache, false);

    // If the event has already fired and we missed it, clear/refresh the pickyfill cache.
    if(applicationCache.status === applicationCache.UPDATEREADY) {
        refreshCache();
    }

    if (applicationCache.status === applicationCache.OBSOLETE) {
        clearCache();
    }

    var srcFromCacheRan = false;
    var srcFromCache = function ( ps ) {
        var sources, src, newSrc;

        // Loop the pictures
        for( var i = 0, il = ps.length; i < il; i++ ){
            if( ps[ i ].getAttribute( "data-picture" ) !== null ){

                sources = ps[ i ].getElementsByTagName( "div" );
                // See which ones are cached in localStorage. Use the cached value.
                for( var j = 0, jl = sources.length; j < jl; j++ ){
                    if ((src = sources[j].getAttribute( "data-src" )) !== null ) {
                        if ( pf_index.hasOwnProperty('pf_s_' + src)) {
                            newSrc = localStorage.getItem('pf_s_' + src);
                            if (newSrc !== null) {
                                sources[j].setAttribute('data-src', localStorage.getItem('pf_s_' + src));
                            }
                        }
                    }
                }
            }
        }
    };

    var cacheImage = function () {
        var canvas, ctx, imageSrc;

        imageSrc = this.getAttribute("src");
        // Check for "data:" because sometimes it slips through.
        // TODO: Figure out why "someimtes it slips through".
        if ((imageSrc === null) || (imageSrc.length === 0) || (imageSrc.substr(0,5) === "data:")) {
            return;
        }

        canvas = w.document.createElement("canvas");
        canvas.width = this.width;
        canvas.height = this.height;

        ctx = canvas.getContext("2d");
        ctx.drawImage(this, 0, 0);
        try {
            dataUri = canvas.toDataURL();

        } catch (e) {
            // TODO: Improve error handling here. For now, if canvas.toDataURL()
            //   throws an exception, don't cache the image and move on.
            return;
        }

        // Do not cache if the resulting cache item will take more than 128Kb.
        if (dataUri.length > 131072) {
            return;
        }

        pf_index["pf_s_"+imageSrc] = 1;

        try {
            localStorage.setItem("pf_s_"+imageSrc, dataUri);
            localStorage.setItem("pf_index", JSON.stringify(pf_index));
        } catch (e) {
            // Caching failed. Remove item from index object so next cached item
            //   doesn't wrongly indicate this item was successfully cached.
            delete pf_index["pf_s_"+imageSrc];
        }
    };

    w.picturefillOrig = w.picturefill;
    w.picturefill = function () {
        var ps = w.document.getElementsByTagName( "div" );

        if (! srcFromCacheRan ) {
            srcFromCacheRan = true;
            srcFromCache( ps );
        }

        w.picturefillOrig();

        // Loop the pictures
        for( var i = 0, il = ps.length; i < il; i++ ){
            if( ps[ i ].getAttribute( "data-picture" ) !== null ){

                image = ps[ i ].getElementsByTagName( "img" )[0];
                if (image) {
                    if ((imageSrc = image.getAttribute("src")) !== null) {
                        if (imageSrc.substr(0,5) !== "data:") {
                            image.addEventListener("load", cacheImage, false);
                        }
                    }
                }
            }
        }
    };

}( this ));
<commit_msg>Accommodate FF 14.0.1 on the Mac. :-/<commit_after>/*! Pickyfill - Offline caching for picturefill responsive image polyfill. Author: Rich Trott | Copyright: Regents of University of California, 2012 | License: MIT */

(function( w ) {
    "use strict";

    var localStorage = w.localStorage,
        applicationCache = w.applicationCache,
        image,
        imageSrc,
        dataUri,
        pf_index_string,
        pf_index,
        canvasTest = document.createElement('canvas');

    // Don't run any of this stuff if application cache doesn't exist or isn't being used,
    //     or localStorage or canvas are not available.
    if ( (! applicationCache) || (applicationCache.status === applicationCache.UNCACHED) ||
        (! localStorage) || (!(canvasTest.getContext && canvasTest.getContext('2d'))) ) {
            return;
    }

    pf_index_string = localStorage.getItem('pf_index') || '{}';
    pf_index = JSON.parse(pf_index_string);

    // We'll use this to clear the pickyfill cache when appcache updates.
    var clearCache = function () {
        localStorage.removeItem('pf_index');
        for (var prop in pf_index) {
            localStorage.removeItem(prop);
        }
    };

    // Unfortunately, reloading is the most reliable way to get stuff into the
    //  pickyfill cache. If you wait for the user to reload, they may be offline
    //  at that time. If we just had an updateready event, chances are very good
    //  that they are still online. Another possibility is to just try to reload
    //  the images that are currently shown, but there's no guarantee that those
    //  images are in the new page or that the current page isn't missing important
    //  images that will display in the new page and need to be cached.
    var refreshCache = function () {
        clearCache();
        w.location.reload();
    };

    var removeSelf = function () {
        var imageSrc = this.getAttribute("src");
        delete pf_index[imageSrc];
        localStorage.removeItem(imageSrc);
        try {
            localStorage.setItem("pf_index", JSON.stringify(pf_index));
        }
        catch (e) {
            //TODO: What to do if setItem() fails here?
        }
    };

    // If appcache updates, refresh the pickyfill cache to get new items.
    // If appcache is obsolete, clear the pickyfill cache.
    // Appcache == IE10 or later == no need to worry about attachEvent (IE8 and earlier)
    // Anything that has appcache is going to have addEventListener.
    applicationCache.addEventListener('updateready', refreshCache, false);
    applicationCache.addEventListener('obsolete', clearCache, false);

    // If the event has already fired and we missed it, clear/refresh the pickyfill cache.
    if(applicationCache.status === applicationCache.UPDATEREADY) {
        refreshCache();
    }

    if (applicationCache.status === applicationCache.OBSOLETE) {
        clearCache();
    }

    var srcFromCacheRan = false;
    var srcFromCache = function ( ps ) {
        var sources, src, newSrc;

        // Loop the pictures
        for( var i = 0, il = ps.length; i < il; i++ ){
            if( ps[ i ].getAttribute( "data-picture" ) !== null ){

                sources = ps[ i ].getElementsByTagName( "div" );
                // See which ones are cached in localStorage. Use the cached value.
                for( var j = 0, jl = sources.length; j < jl; j++ ){
                    if ((src = sources[j].getAttribute( "data-src" )) !== null ) {
                        if ( pf_index.hasOwnProperty('pf_s_' + src)) {
                            newSrc = localStorage.getItem('pf_s_' + src);
                            if (newSrc !== null) {
                                sources[j].setAttribute('data-src', localStorage.getItem('pf_s_' + src));
                            }
                        }
                    }
                }
            }
        }
    };

    var cacheImage = function () {
        var canvas, ctx, imageSrc;

        imageSrc = this.getAttribute("src");
        // Check for "data:" because sometimes it slips through.
        // TODO: Figure out why "someimtes it slips through". (Happens on FF 14.0.1 on Mac at least.)
        if ((imageSrc === null) || (imageSrc.length === 0) || (imageSrc.substr(0,5) === "data:")) {
            return;
        }

        canvas = w.document.createElement("canvas");
        canvas.width = this.width;
        canvas.height = this.height;

        ctx = canvas.getContext("2d");
        ctx.drawImage(this, 0, 0);
        try {
            dataUri = canvas.toDataURL();
        } catch (e) {
            // TODO: Improve error handling here. For now, if canvas.toDataURL()
            //   throws an exception, don't cache the image and move on.
            return;
        }

        // Do not cache if the resulting cache item will take more than 128Kb.
        if (dataUri.length > 131072) {
            return;
        }

        pf_index["pf_s_"+imageSrc] = 1;

        try {
            localStorage.setItem("pf_s_"+imageSrc, dataUri);
            localStorage.setItem("pf_index", JSON.stringify(pf_index));
        } catch (e) {
            // Caching failed. Remove item from index object so next cached item
            //   doesn't wrongly indicate this item was successfully cached.
            delete pf_index["pf_s_"+imageSrc];
        }
    };

    w.picturefillOrig = w.picturefill;
    w.picturefill = function () {
        var ps = w.document.getElementsByTagName( "div" );

        if (! srcFromCacheRan ) {
            srcFromCacheRan = true;
            srcFromCache( ps );
        }

        w.picturefillOrig();

        // Loop the pictures
        for( var i = 0, il = ps.length; i < il; i++ ){
            if( ps[ i ].getAttribute( "data-picture" ) !== null ){

                image = ps[ i ].getElementsByTagName( "img" )[0];
                if (image) {
                    if ((imageSrc = image.getAttribute("src")) !== null) {
                        if (imageSrc.substr(0,5) !== "data:") {
                            image.addEventListener("load", cacheImage, false);
                            image.addEventListener("error", removeSelf, false);
                        }
                    }
                }
            }
        }
    };

}( this ));
<|endoftext|>


<commit_before>var ConfigModel = require('../../../../javascripts/cartodb3/data/config-model');
var ExportMapDefinitionModel = require('../../../../javascripts/cartodb3/data/export-map-definition-model');

describe('data/export-map-definition-model', function () {
  beforeEach(function () {
    var configModel = new ConfigModel({
      base_url: '/u/manolo'
    });
    this.model = new ExportMapDefinitionModel({
      visualization_id: 'v-123',
    }, {
      configModel: configModel
    });

    spyOn(this.model, 'save');
    spyOn(this.model, '_interrupt');
  });

  it('should request an export', function () {
    this.model.requestExport();

    expect(this.model.save).toHaveBeenCalled();
  });

  it('should cancel an export', function () {
    this.model.cancelExport();

    expect(this.model._interrupt).toHaveBeenCalled();
  });

  it('should have correct url', function () {
    expect(this.model.urlRoot()).toBe('/u/manolo/api/v3/visualization_exports');
  });
});
<commit_msg>remove trailling comma<commit_after>var ConfigModel = require('../../../../javascripts/cartodb3/data/config-model');
var ExportMapDefinitionModel = require('../../../../javascripts/cartodb3/data/export-map-definition-model');

describe('data/export-map-definition-model', function () {
  beforeEach(function () {
    var configModel = new ConfigModel({
      base_url: '/u/manolo'
    });
    this.model = new ExportMapDefinitionModel({
      visualization_id: 'v-123'
    }, {
      configModel: configModel
    });

    spyOn(this.model, 'save');
    spyOn(this.model, '_interrupt');
  });

  it('should request an export', function () {
    this.model.requestExport();

    expect(this.model.save).toHaveBeenCalled();
  });

  it('should cancel an export', function () {
    this.model.cancelExport();

    expect(this.model._interrupt).toHaveBeenCalled();
  });

  it('should have correct url', function () {
    expect(this.model.urlRoot()).toBe('/u/manolo/api/v3/visualization_exports');
  });
});
<|endoftext|>


<commit_before>export function getDiskXML(poolName, volumeName, format, target, cacheMode, shareable, busType) {
    var doc = document.implementation.createDocument('', '', null);

    var diskElem = doc.createElement('disk');
    diskElem.setAttribute('type', 'volume');
    diskElem.setAttribute('device', 'disk');

    var driverElem = doc.createElement('driver');
    driverElem.setAttribute('name', 'qemu');
    if (format && ['qcow2', 'raw'].includes(format))
        driverElem.setAttribute('type', format);
    driverElem.setAttribute('cache', cacheMode);
    diskElem.appendChild(driverElem);

    var sourceElem = doc.createElement('source');
    sourceElem.setAttribute('volume', volumeName);
    sourceElem.setAttribute('pool', poolName);
    diskElem.appendChild(sourceElem);

    var targetElem = doc.createElement('target');
    targetElem.setAttribute('dev', target);
    targetElem.setAttribute('bus', busType);
    diskElem.appendChild(targetElem);

    if (shareable) {
        const shareableElem = doc.createElement('shareable');
        diskElem.appendChild(shareableElem);
    }

    doc.appendChild(diskElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}

export function getIfaceXML(sourceType, source, model, mac) {
    const doc = document.implementation.createDocument('', '', null);

    const ifaceElem = doc.createElement('interface');
    ifaceElem.setAttribute('type', sourceType);

    const sourceElem = doc.createElement('source');
    if (sourceType === "network")
        sourceElem.setAttribute('network', source);
    else if (sourceType === "direct")
        sourceElem.setAttribute('dev', source);
    else if (sourceType === "bridge")
        sourceElem.setAttribute('bridge', source);
    ifaceElem.appendChild(sourceElem);

    if (mac) {
        const macElem = doc.createElement('mac');
        macElem.setAttribute('address', mac);
        ifaceElem.appendChild(macElem);
    }

    const modelElem = doc.createElement('model');
    modelElem.setAttribute('type', model);
    ifaceElem.appendChild(modelElem);

    doc.appendChild(ifaceElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}

export function getNetworkXML({ name, forwardMode, device, ipv4, netmask, ipv6, prefix, ipv4DhcpRangeStart, ipv4DhcpRangeEnd, ipv6DhcpRangeStart, ipv6DhcpRangeEnd }) {
    const doc = document.implementation.createDocument('', '', null);

    const networkElem = doc.createElement('network');

    const nameElem = doc.createElement('name');
    nameElem.appendChild(doc.createTextNode(name));
    networkElem.appendChild(nameElem);

    if (forwardMode !== 'none') {
        const forwardElem = doc.createElement('forward');
        forwardElem.setAttribute('mode', forwardMode);
        if ((forwardMode === 'nat' || forwardMode === 'route') && device !== 'automatic')
            forwardElem.setAttribute('dev', device);
        networkElem.appendChild(forwardElem);
    }

    if (forwardMode === 'none' ||
        forwardMode === 'nat' ||
        forwardMode === 'route' ||
        forwardMode === 'open') {
        const domainElem = doc.createElement('domain');
        domainElem.setAttribute('name', name);
        domainElem.setAttribute('localOnly', 'yes');
        networkElem.appendChild(domainElem);
    }

    if (ipv4) {
        const dnsElem = doc.createElement('dns');
        const hostElem = doc.createElement('host');
        hostElem.setAttribute('ip', ipv4);
        const hostnameElem = doc.createElement('hostname');
        const hostnameTextNode = doc.createTextNode('gateway');
        hostnameElem.appendChild(hostnameTextNode);
        hostElem.appendChild(hostnameElem);
        dnsElem.appendChild(hostElem);
        networkElem.appendChild(dnsElem);

        const ipElem = doc.createElement('ip');
        ipElem.setAttribute('address', ipv4);
        ipElem.setAttribute('netmask', netmask);
        networkElem.appendChild(ipElem);

        if (ipv4DhcpRangeStart) {
            const dhcpElem = doc.createElement('dhcp');
            ipElem.appendChild(dhcpElem);

            const rangeElem = doc.createElement('range');
            rangeElem.setAttribute('start', ipv4DhcpRangeStart);
            rangeElem.setAttribute('end', ipv4DhcpRangeEnd);
            dhcpElem.appendChild(rangeElem);
        }
    }

    if (ipv6) {
        const ipv6Elem = doc.createElement('ip');
        ipv6Elem.setAttribute('family', 'ipv6');
        ipv6Elem.setAttribute('address', ipv6);
        ipv6Elem.setAttribute('prefix', prefix);
        networkElem.appendChild(ipv6Elem);

        if (ipv6DhcpRangeStart) {
            const dhcpElem = doc.createElement('dhcp');
            ipv6Elem.appendChild(dhcpElem);

            const rangeElem = doc.createElement('range');
            rangeElem.setAttribute('start', ipv6DhcpRangeStart);
            rangeElem.setAttribute('end', ipv6DhcpRangeEnd);
            dhcpElem.appendChild(rangeElem);
        }
    }

    doc.appendChild(networkElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}

export function getVolumeXML(volumeName, size, format) {
    var doc = document.implementation.createDocument('', '', null);

    var volElem = doc.createElement('volume');
    volElem.setAttribute('type', 'file');

    var nameElem = doc.createElement('name');
    nameElem.appendChild(doc.createTextNode(volumeName));
    volElem.appendChild(nameElem);

    var allocationElem = doc.createElement('capacity');
    allocationElem.setAttribute('unit', 'MiB');
    allocationElem.appendChild(doc.createTextNode(size));
    volElem.appendChild(allocationElem);

    var targetElem = doc.createElement('target');

    if (format) {
        var formatElem = doc.createElement('format');
        formatElem.setAttribute('type', format);
        targetElem.appendChild(formatElem);
    }

    volElem.appendChild(targetElem);

    doc.appendChild(volElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}

export function getPoolXML({ name, type, source, target }) {
    const doc = document.implementation.createDocument('', '', null);

    const poolElem = doc.createElement('pool');
    poolElem.setAttribute('type', type);

    const nameElem = doc.createElement('name');
    nameElem.appendChild(doc.createTextNode(name));
    poolElem.appendChild(nameElem);

    if (target) {
        const targetElem = doc.createElement('target');
        const pathElem = doc.createElement('path');
        pathElem.appendChild(doc.createTextNode(target));
        targetElem.appendChild(pathElem);
        poolElem.appendChild(targetElem);
    }

    const sourceElem = doc.createElement('source');
    if (source.dir) {
        const dirElem = doc.createElement('dir');

        dirElem.setAttribute('path', source.dir);
        sourceElem.appendChild(dirElem);
    }
    if (source.device) {
        const deviceElem = doc.createElement('device');

        deviceElem.setAttribute('path', source.device);
        sourceElem.appendChild(deviceElem);
    }
    if (source.name) {
        const sourceNameElem = doc.createElement('name');

        sourceNameElem.appendChild(doc.createTextNode(source.name));
        sourceElem.appendChild(sourceNameElem);
    }
    if (source.host) {
        const hostElem = doc.createElement('host');

        hostElem.setAttribute('name', source.host);
        sourceElem.appendChild(hostElem);
    }
    if (source.initiator) {
        const initiatorElem = doc.createElement('initiator');
        const iqnElem = doc.createElement('iqn');

        iqnElem.setAttribute('name', source.initiator);
        initiatorElem.appendChild(iqnElem);
        sourceElem.appendChild(initiatorElem);
    }
    if (source.format) {
        const formatElem = doc.createElement('format');

        formatElem.setAttribute('type', source.format);
        sourceElem.appendChild(formatElem);
    }
    if (source.host || source.dir || source.device || source.name || source.initiator || source.format)
        poolElem.appendChild(sourceElem);

    doc.appendChild(poolElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}

export function getSnapshotXML(name, description) {
    const doc = document.implementation.createDocument('', '', null);

    const snapElem = doc.createElement('domainsnapshot');

    if (name) {
        const nameElem = doc.createElement('name');
        nameElem.appendChild(doc.createTextNode(name));
        snapElem.appendChild(nameElem);
    }

    if (description) {
        const descriptionElem = doc.createElement('description');
        descriptionElem.appendChild(doc.createTextNode(description));
        snapElem.appendChild(descriptionElem);
    }

    doc.appendChild(snapElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}
<commit_msg>machines: DNS PTR record for this virtual IP network<commit_after>export function getDiskXML(poolName, volumeName, format, target, cacheMode, shareable, busType) {
    var doc = document.implementation.createDocument('', '', null);

    var diskElem = doc.createElement('disk');
    diskElem.setAttribute('type', 'volume');
    diskElem.setAttribute('device', 'disk');

    var driverElem = doc.createElement('driver');
    driverElem.setAttribute('name', 'qemu');
    if (format && ['qcow2', 'raw'].includes(format))
        driverElem.setAttribute('type', format);
    driverElem.setAttribute('cache', cacheMode);
    diskElem.appendChild(driverElem);

    var sourceElem = doc.createElement('source');
    sourceElem.setAttribute('volume', volumeName);
    sourceElem.setAttribute('pool', poolName);
    diskElem.appendChild(sourceElem);

    var targetElem = doc.createElement('target');
    targetElem.setAttribute('dev', target);
    targetElem.setAttribute('bus', busType);
    diskElem.appendChild(targetElem);

    if (shareable) {
        const shareableElem = doc.createElement('shareable');
        diskElem.appendChild(shareableElem);
    }

    doc.appendChild(diskElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}

export function getIfaceXML(sourceType, source, model, mac) {
    const doc = document.implementation.createDocument('', '', null);

    const ifaceElem = doc.createElement('interface');
    ifaceElem.setAttribute('type', sourceType);

    const sourceElem = doc.createElement('source');
    if (sourceType === "network")
        sourceElem.setAttribute('network', source);
    else if (sourceType === "direct")
        sourceElem.setAttribute('dev', source);
    else if (sourceType === "bridge")
        sourceElem.setAttribute('bridge', source);
    ifaceElem.appendChild(sourceElem);

    if (mac) {
        const macElem = doc.createElement('mac');
        macElem.setAttribute('address', mac);
        ifaceElem.appendChild(macElem);
    }

    const modelElem = doc.createElement('model');
    modelElem.setAttribute('type', model);
    ifaceElem.appendChild(modelElem);

    doc.appendChild(ifaceElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}

export function getNetworkXML({ name, forwardMode, device, ipv4, netmask, ipv6, prefix, ipv4DhcpRangeStart, ipv4DhcpRangeEnd, ipv6DhcpRangeStart, ipv6DhcpRangeEnd }) {
    const doc = document.implementation.createDocument('', '', null);

    const networkElem = doc.createElement('network');

    const nameElem = doc.createElement('name');
    nameElem.appendChild(doc.createTextNode(name));
    networkElem.appendChild(nameElem);

    if (forwardMode !== 'none') {
        const forwardElem = doc.createElement('forward');
        forwardElem.setAttribute('mode', forwardMode);
        if ((forwardMode === 'nat' || forwardMode === 'route') && device !== 'automatic')
            forwardElem.setAttribute('dev', device);
        networkElem.appendChild(forwardElem);
    }

    if (forwardMode === 'none' ||
        forwardMode === 'nat' ||
        forwardMode === 'route' ||
        forwardMode === 'open') {
        const domainElem = doc.createElement('domain');
        domainElem.setAttribute('name', name);
        domainElem.setAttribute('localOnly', 'yes');
        networkElem.appendChild(domainElem);
    }

    if (ipv4) {
        const dnsElem = doc.createElement('dns');
        const hostElem = doc.createElement('host');
        hostElem.setAttribute('ip', ipv4);
        const hostnameElem = doc.createElement('hostname');
        const hostnameTextNode = doc.createTextNode('gateway');
        hostnameElem.appendChild(hostnameTextNode);
        hostElem.appendChild(hostnameElem);
        dnsElem.appendChild(hostElem);
        networkElem.appendChild(dnsElem);

        const ipElem = doc.createElement('ip');
        ipElem.setAttribute('address', ipv4);
        ipElem.setAttribute('netmask', netmask);
        ipElem.setAttribute('localPtr', 'yes');
        networkElem.appendChild(ipElem);

        if (ipv4DhcpRangeStart) {
            const dhcpElem = doc.createElement('dhcp');
            ipElem.appendChild(dhcpElem);

            const rangeElem = doc.createElement('range');
            rangeElem.setAttribute('start', ipv4DhcpRangeStart);
            rangeElem.setAttribute('end', ipv4DhcpRangeEnd);
            dhcpElem.appendChild(rangeElem);
        }
    }

    if (ipv6) {
        const ipv6Elem = doc.createElement('ip');
        ipv6Elem.setAttribute('family', 'ipv6');
        ipv6Elem.setAttribute('address', ipv6);
        ipv6Elem.setAttribute('prefix', prefix);
        networkElem.appendChild(ipv6Elem);

        if (ipv6DhcpRangeStart) {
            const dhcpElem = doc.createElement('dhcp');
            ipv6Elem.appendChild(dhcpElem);

            const rangeElem = doc.createElement('range');
            rangeElem.setAttribute('start', ipv6DhcpRangeStart);
            rangeElem.setAttribute('end', ipv6DhcpRangeEnd);
            dhcpElem.appendChild(rangeElem);
        }
    }

    doc.appendChild(networkElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}

export function getVolumeXML(volumeName, size, format) {
    var doc = document.implementation.createDocument('', '', null);

    var volElem = doc.createElement('volume');
    volElem.setAttribute('type', 'file');

    var nameElem = doc.createElement('name');
    nameElem.appendChild(doc.createTextNode(volumeName));
    volElem.appendChild(nameElem);

    var allocationElem = doc.createElement('capacity');
    allocationElem.setAttribute('unit', 'MiB');
    allocationElem.appendChild(doc.createTextNode(size));
    volElem.appendChild(allocationElem);

    var targetElem = doc.createElement('target');

    if (format) {
        var formatElem = doc.createElement('format');
        formatElem.setAttribute('type', format);
        targetElem.appendChild(formatElem);
    }

    volElem.appendChild(targetElem);

    doc.appendChild(volElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}

export function getPoolXML({ name, type, source, target }) {
    const doc = document.implementation.createDocument('', '', null);

    const poolElem = doc.createElement('pool');
    poolElem.setAttribute('type', type);

    const nameElem = doc.createElement('name');
    nameElem.appendChild(doc.createTextNode(name));
    poolElem.appendChild(nameElem);

    if (target) {
        const targetElem = doc.createElement('target');
        const pathElem = doc.createElement('path');
        pathElem.appendChild(doc.createTextNode(target));
        targetElem.appendChild(pathElem);
        poolElem.appendChild(targetElem);
    }

    const sourceElem = doc.createElement('source');
    if (source.dir) {
        const dirElem = doc.createElement('dir');

        dirElem.setAttribute('path', source.dir);
        sourceElem.appendChild(dirElem);
    }
    if (source.device) {
        const deviceElem = doc.createElement('device');

        deviceElem.setAttribute('path', source.device);
        sourceElem.appendChild(deviceElem);
    }
    if (source.name) {
        const sourceNameElem = doc.createElement('name');

        sourceNameElem.appendChild(doc.createTextNode(source.name));
        sourceElem.appendChild(sourceNameElem);
    }
    if (source.host) {
        const hostElem = doc.createElement('host');

        hostElem.setAttribute('name', source.host);
        sourceElem.appendChild(hostElem);
    }
    if (source.initiator) {
        const initiatorElem = doc.createElement('initiator');
        const iqnElem = doc.createElement('iqn');

        iqnElem.setAttribute('name', source.initiator);
        initiatorElem.appendChild(iqnElem);
        sourceElem.appendChild(initiatorElem);
    }
    if (source.format) {
        const formatElem = doc.createElement('format');

        formatElem.setAttribute('type', source.format);
        sourceElem.appendChild(formatElem);
    }
    if (source.host || source.dir || source.device || source.name || source.initiator || source.format)
        poolElem.appendChild(sourceElem);

    doc.appendChild(poolElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}

export function getSnapshotXML(name, description) {
    const doc = document.implementation.createDocument('', '', null);

    const snapElem = doc.createElement('domainsnapshot');

    if (name) {
        const nameElem = doc.createElement('name');
        nameElem.appendChild(doc.createTextNode(name));
        snapElem.appendChild(nameElem);
    }

    if (description) {
        const descriptionElem = doc.createElement('description');
        descriptionElem.appendChild(doc.createTextNode(description));
        snapElem.appendChild(descriptionElem);
    }

    doc.appendChild(snapElem);

    return new XMLSerializer().serializeToString(doc.documentElement);
}
<|endoftext|>