<commit_before>var Disassembler = Disassembler || {};

(function() {
  'use strict';

  // Pad the number 'n' to with padding character 'z' to width 'width'.
  function pad(n, width, z, tail) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : tail ?
      n + new Array(width - n.length + 1).join(z) :
      new Array(width - n.length + 1).join(z) + n;
  }

  var programContainsRoutines = false;

  // An instruction
  var Instruction = function(instruction, address, comment) {

    if (instruction.length != 8 || !instruction.match(/[0-9a-fA-F]{8}/)) {
      throw "Invalid instruction '" + instruction + "'";
    }

    var bytes = function(number) {
      var p = [];

      for (var i = Math.floor(number.length / 2); i-->0;)
        p[i] = number.slice(i * 2, (i + 1) * 2);

      return p;
    }(instruction);

    this.binary = instruction;
    this.address = address;
    this.addressHex = pad(address.toString(16), 8).toUpperCase();
    this.next = [this.address + 1];

    if (comment !== undefined)
      this.comment = comment;

    var address = bytes[1] + bytes[2] + bytes[3];
    var jumpAddress = parseInt(address, 16) - idtLength;

    switch (parseInt(bytes[0], 16)) {
    case 0:
      this.mnemonic = 'iuc';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'No operation';
      break;
    case 1:
      this.mnemonic = 'huc';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'Terminate';
      break;
    case 2:
      this.mnemonic = 'buc';
      this.instruction = this.mnemonic.toUpperCase() + '  ' + address;
      this.desc = 'Jump to ' + address;
      this.next = [jumpAddress];
      break;
    case 3:
      this.mnemonic = 'bic';
      this.instruction = this.mnemonic.toUpperCase() + '  ' + address;
      this.desc = 'Jump to ' + address + ' if condition flag is set';
      this.next.push(jumpAddress);
      break;
    case 4:
      this.mnemonic = 'seto 0x' + bytes[1] + ', 0x' +
        bytes[2] + ', 0x' + bytes[3];
      this.instruction = 'SETO ' + bytes[1] + bytes[2] + bytes[3];
      this.desc = 'Set outputs ' + bytes[1] + ' AND ' + bytes[2] + ' XOR ' + bytes[3];
      break;
    case 5:
      this.mnemonic = 'tsti 0x' + bytes[1] + ', 0x' +
        bytes[2] + ', 0x' + bytes[3];
      this.instruction = 'TSTI ' + bytes[1] + bytes[2] + bytes[3];
      this.desc = 'Test input port ' + parseInt(bytes[1], 16) + ' AND ' +
        bytes[2] + ' XOR ' + bytes[3];
      break;
    case 6:
      this.mnemonic = 'bsr';
      this.instruction = this.mnemonic.toUpperCase() + '  ' + address;
      this.desc = 'Call subroutine ' + address;
      this.next = [jumpAddress];
      programContainsRoutines = true; // Shit!
      break;
    case 7:
      this.mnemonic = 'rsr';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'Return from subroutine';
      break;
    case 8:
      this.mnemonic = 'rir';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'Return from interrupt';
      break;
    case 9:
      this.mnemonic = 'sei';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'Enable interrupts';
      break;
    case 10:
      this.mnemonic = 'cli';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'Disable interrupts';
      break;
    default:
      throw "Invalid opcode '" + bytes[0] + "'";
    };

    this.getLabel = function(type) {
      if (this.label === undefined) {
        if (type == 'routine')
          this.label = new RoutineLabel();
        else if (type == 'interrupt')
          this.label = new HandlerLabel();
        else
          this.label = new Label();
      }

      return this.label;
    };

    this.toString = function(instructions) {
      var label = this.label ? this.getLabel().toString() + '\n' : '';
      var string = '        ';

      if (this.next[0] !== this.address + 1) {
        string += this.mnemonic + '  ';

        if (this.address < idtLength) // Interrupt handler
          string += instructions[this.next[0]].getLabel('interrupt').name;
        else if (this.mnemonic == 'bsr')
          string += instructions[this.next[0]].getLabel('routine').name;
        else // Jump instruction
          string += instructions[this.next[0]].getLabel().name;

      } else if (this.next[1] !== undefined) // Branch instruction
        string += this.mnemonic + '  ' + instructions[this.next[1]].getLabel().name;
      else
        string += this.mnemonic;

      if (this.comment) // Add inline comment at character 32
        string = pad(string, 31, ' ', true) + ' ; ' + this.comment;

      return label + string;
    };
  };

  var Section = function(name) {
    this.toString = function() {
      return 'SECTION .' + name;
    };
  };

  var Comment = function(text) {
    this.toString = function() {
      return ';; ' + text;
    };
  };

  var BlankLine = function() {
    this.toString = function() {
      return '  ';
    };
  };

  var _labelCounter = 0; // Used for automatic label naming
  var _routineCounter = 0; // Used for automatic interrupt label naming
  var _handlerCounter = 0; // Used for automatic interrupt label naming

  var Label = function(name) {
    this.name = name ? name : 'label' + _labelCounter++;

    this.toString = function() {
      return this.name + ':';
    };
  };

  var RoutineLabel = function(name) {
    this.name = name ? name : 'subroutine' + _routineCounter++;

    this.toString = function() {
      return this.name + ':';
    };
  };

  var HandlerLabel = function(name) {
    this.name = name ? name : 'irq' + _handlerCounter++;

    this.toString = function() {
      return this.name + ':';
    };
  };

  var $code = $('#code');
  var $errors = $('#errors');
  var $warnings = $('#warnings');
  var $output = $('#output');

  var idtLength = 8; // Interrupt Descriptor Table length (in words)

  // Decode an array of strings, one instruction per string
  var decode = function(text) {

    var instructions = [], idt = [], address = 0, string = '', i = 0;

    try { // Parse instructions
      for (i = 0; i < text.length; i++) {
        string = text[i].trim();

        if (string.length) {
          if (i < idtLength) { // Interrupt descriptor
            idt.push(new Instruction(string, address++,
                                     'Interrupt handler ' + i));
          } else { // Instruction
            instructions.push(new Instruction(string, address++));
          }
        }
      }
    } catch (err) { // Stop decoding on first error
      addError("At line " + i + ": " + err);
    }

    if (programContainsRoutines)
      addWarning("No code visualisation " +
                 "Sorry, the code visualiser can't handle programs which " +
                 "contain subroutines.");

    return {
      instructions: instructions,
      idt: idt
    };
  }

  var instructionsToChart = function(instructions) {
    var definitions = "st=>start: Start\ne=>end: End\n", links = "";

    var instructionDefinition = function(instruction, i) {
      if (instruction.next[1] !== undefined) // Conditional instruction
        return "i" + i + "=>condition: " + instruction.instruction + "\n";
      else // Unconditional instruction
        return "i" + i + "=>operation: " + instruction.instruction + "\n";
    };

    var instructionLinks = function(instruction, i) {
      if (instruction.next[1] !== undefined) { // Conditional instruction
        var links = "";

        if (instruction.next[0] !== -1) // Valid address
          links = "i" + i + "(no)->i" + instruction.next[0] + "\n";
        if (instruction.next[1] !== -1) // Valid address
          links += "i" + i + "(yes, right)->i" + instruction.next[1] + "\n";

        return links
      } else {
        if (instruction.next[0] !== -1) // Valid address
          return "i" + i + "->i" + instruction.next[0] + "\n";
        else
          return "";
      }
    }

    var lastAddress = instructions.length + idtLength, instruction = '';

    if (instructions.length) // Start and end symbols
      links += "st->i" + idtLength + "\ni" + (lastAddress - 1) + "->e\n";

    for (var i = idtLength; i < lastAddress; i++) {
      instruction = instructions[i - idtLength];

      // Check for valid addresses
      if (instruction.next[0] >= lastAddress)
        instruction.next[0] = -1;

      if (instruction.next[1] >= lastAddress)
        instruction.next[1] = -1;

      definitions += instructionDefinition(instruction, i);
      links += instructionLinks(instruction, i);
    }

    return definitions + links;
  }

  var showAssembly = function(data) {
    var instructions = data.instructions;
    var idt = data.idt;
    var prog = [new Comment('Generated assembly, see:'),
                new Comment('    http://chriscummins.cc/disassembler'),
                new Comment(''),
                new BlankLine()];
    var string = '';

    if (idt.length) { // Show interrupt table label
      prog.push(new Section('data'));
      prog.push(new BlankLine());

      idt[0].label = new Label('interrupt_vectors');
      idt.forEach(function(e) {
        prog.push(e);
      });

      prog.push(new BlankLine());
    }

    prog.push(new Section('text'));
    prog.push(new BlankLine());

    if (instructions.length) // Set special "start" label
      instructions[0].label = new Label('start');

    instructions.forEach(function(e) {
      prog.push(e);
    });

    // Generate label cross references
    prog.forEach(function(e) {
      try {
        e.toString(instructions);
      } catch (err) {
        addError("At address " + e.addressHex +
                 ": Branch address out of bounds!")
      }
    });

    prog.push(new BlankLine());
    prog.push(new Comment('End of program code'))

    // Display table
    prog.forEach(function(e) {
      try {
        addInstruction(e, instructions);
      } catch (e) {}
    });
  };

  var _diagram; // The flowchart

  // Display an array of instructions
  var show = function(data) {

    var instructions = data.instructions;
    var idt = data.idt;

    showAssembly(data);

    if (idt.length || instructions.length)
      $('#code-output').show();
    else
      $('#code-output').hide();

    if (!programContainsRoutines && instructions.length) { // Only draw the flowchart if we can
      $('#diagram').show();

      if (_diagram)
        _diagram.clean();

      _diagram = flowchart.parse(instructionsToChart(instructions));
      _diagram.drawSVG('diagram');
    } else {
      $('#diagram').hide();
    }
  };

  var addError = function(msg) {
    $errors.append("
" + msg +
                   "×
");
  };

  var addWarning = function(msg) {
    $warnings.append("
" + msg +
                     "×
");
  };

  var addInstruction = function(instruction, instructions) {
    var addRow = function(address, instruction, caption) {
      $output.append('

' + address +
                     '

' +
                     instruction + '

');
    };

    var address = instruction.address === undefined ?
      '' : instruction.addressHex;
    var caption = instruction.desc === undefined ? '' : instruction.desc;
    var lines = instruction.toString(instructions).split('\n');

    if (lines.length > 1) { // Instruction contains label
      addRow('', lines[0], '');
      addRow(address, lines[1], caption);
    } else {
      addRow(address, lines[0], caption);
    };
  };

  var refresh = function() { // Refresh display
    $errors.html('');
    $warnings.html('');
    $output.html('');
    _labelCounter = 0;
    _routineCounter = 0;
    _handlerCounter = 0;
    programContainsRoutines = false;

    show(decode($code.val().split("\n")));
  };

  // Update as the user types
  $code.bind('input propertychange', function() {
    refresh();
  });

  $('#idt-enable').change(function() {
    idtLength = parseInt($('#idt-enable option:selected').val());
    refresh();
  });

}).call(Disassembler);
<commit_msg>js/disassembler: Increase gap between op and args<commit_after>var Disassembler = Disassembler || {};

(function() {
  'use strict';

  // Pad the number 'n' to with padding character 'z' to width 'width'.
  function pad(n, width, z, tail) {
    z = z || '0';
    n = n + '';
    return n.length >= width ? n : tail ?
      n + new Array(width - n.length + 1).join(z) :
      new Array(width - n.length + 1).join(z) + n;
  }

  var programContainsRoutines = false;

  // An instruction
  var Instruction = function(instruction, address, comment) {

    if (instruction.length != 8 || !instruction.match(/[0-9a-fA-F]{8}/)) {
      throw "Invalid instruction '" + instruction + "'";
    }

    var bytes = function(number) {
      var p = [];

      for (var i = Math.floor(number.length / 2); i-->0;)
        p[i] = number.slice(i * 2, (i + 1) * 2);

      return p;
    }(instruction);

    this.binary = instruction;
    this.address = address;
    this.addressHex = pad(address.toString(16), 8).toUpperCase();
    this.next = [this.address + 1];

    if (comment !== undefined)
      this.comment = comment;

    var address = bytes[1] + bytes[2] + bytes[3];
    var jumpAddress = parseInt(address, 16) - idtLength;

    switch (parseInt(bytes[0], 16)) {
    case 0:
      this.mnemonic = 'iuc';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'No operation';
      break;
    case 1:
      this.mnemonic = 'huc';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'Terminate';
      break;
    case 2:
      this.mnemonic = 'buc';
      this.instruction = this.mnemonic.toUpperCase() + '    ' + address;
      this.desc = 'Jump to ' + address;
      this.next = [jumpAddress];
      break;
    case 3:
      this.mnemonic = 'bic';
      this.instruction = this.mnemonic.toUpperCase() + '    ' + address;
      this.desc = 'Jump to ' + address + ' if condition flag is set';
      this.next.push(jumpAddress);
      break;
    case 4:
      this.mnemonic = 'seto   0x' + bytes[1] + ', 0x' +
        bytes[2] + ', 0x' + bytes[3];
      this.instruction = 'SETO ' + bytes[1] + bytes[2] + bytes[3];
      this.desc = 'Set outputs ' + bytes[1] + ' AND ' + bytes[2] + ' XOR ' + bytes[3];
      break;
    case 5:
      this.mnemonic = 'tsti   0x' + bytes[1] + ', 0x' +
        bytes[2] + ', 0x' + bytes[3];
      this.instruction = 'TSTI ' + bytes[1] + bytes[2] + bytes[3];
      this.desc = 'Test input port ' + parseInt(bytes[1], 16) + ' AND ' +
        bytes[2] + ' XOR ' + bytes[3];
      break;
    case 6:
      this.mnemonic = 'bsr';
      this.instruction = this.mnemonic.toUpperCase() + '  ' + address;
      this.desc = 'Call subroutine ' + address;
      this.next = [jumpAddress];
      programContainsRoutines = true; // Shit!
      break;
    case 7:
      this.mnemonic = 'rsr';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'Return from subroutine';
      break;
    case 8:
      this.mnemonic = 'rir';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'Return from interrupt';
      break;
    case 9:
      this.mnemonic = 'sei';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'Enable interrupts';
      break;
    case 10:
      this.mnemonic = 'cli';
      this.instruction = this.mnemonic.toUpperCase();
      this.desc = 'Disable interrupts';
      break;
    default:
      throw "Invalid opcode '" + bytes[0] + "'";
    };

    this.getLabel = function(type) {
      if (this.label === undefined) {
        if (type == 'routine')
          this.label = new RoutineLabel();
        else if (type == 'interrupt')
          this.label = new HandlerLabel();
        else
          this.label = new Label();
      }

      return this.label;
    };

    this.toString = function(instructions) {
      var label = this.label ? this.getLabel().toString() + '\n' : '';
      var string = '        ';

      if (this.next[0] !== this.address + 1) {
        string += this.mnemonic + '    ';

        if (this.address < idtLength) // Interrupt handler
          string += instructions[this.next[0]].getLabel('interrupt').name;
        else if (this.mnemonic == 'bsr')
          string += instructions[this.next[0]].getLabel('routine').name;
        else // Jump instruction
          string += instructions[this.next[0]].getLabel().name;

      } else if (this.next[1] !== undefined) // Branch instruction
        string += this.mnemonic + '    ' + instructions[this.next[1]].getLabel().name;
      else
        string += this.mnemonic;

      if (this.comment) // Add inline comment at character 32
        string = pad(string, 31, ' ', true) + ' ; ' + this.comment;

      return label + string;
    };
  };

  var Section = function(name) {
    this.toString = function() {
      return 'SECTION .' + name;
    };
  };

  var Comment = function(text) {
    this.toString = function() {
      return ';; ' + text;
    };
  };

  var BlankLine = function() {
    this.toString = function() {
      return '  ';
    };
  };

  var _labelCounter = 0; // Used for automatic label naming
  var _routineCounter = 0; // Used for automatic interrupt label naming
  var _handlerCounter = 0; // Used for automatic interrupt label naming

  var Label = function(name) {
    this.name = name ? name : 'label' + _labelCounter++;

    this.toString = function() {
      return this.name + ':';
    };
  };

  var RoutineLabel = function(name) {
    this.name = name ? name : 'subroutine' + _routineCounter++;

    this.toString = function() {
      return this.name + ':';
    };
  };

  var HandlerLabel = function(name) {
    this.name = name ? name : 'irq' + _handlerCounter++;

    this.toString = function() {
      return this.name + ':';
    };
  };

  var $code = $('#code');
  var $errors = $('#errors');
  var $warnings = $('#warnings');
  var $output = $('#output');

  var idtLength = 8; // Interrupt Descriptor Table length (in words)

  // Decode an array of strings, one instruction per string
  var decode = function(text) {

    var instructions = [], idt = [], address = 0, string = '', i = 0;

    try { // Parse instructions
      for (i = 0; i < text.length; i++) {
        string = text[i].trim();

        if (string.length) {
          if (i < idtLength) { // Interrupt descriptor
            idt.push(new Instruction(string, address++,
                                     'Interrupt handler ' + i));
          } else { // Instruction
            instructions.push(new Instruction(string, address++));
          }
        }
      }
    } catch (err) { // Stop decoding on first error
      addError("At line " + i + ": " + err);
    }

    if (programContainsRoutines)
      addWarning("No code visualisation " +
                 "Sorry, the code visualiser can't handle programs which " +
                 "contain subroutines.");

    return {
      instructions: instructions,
      idt: idt
    };
  }

  var instructionsToChart = function(instructions) {
    var definitions = "st=>start: Start\ne=>end: End\n", links = "";

    var instructionDefinition = function(instruction, i) {
      if (instruction.next[1] !== undefined) // Conditional instruction
        return "i" + i + "=>condition: " + instruction.instruction + "\n";
      else // Unconditional instruction
        return "i" + i + "=>operation: " + instruction.instruction + "\n";
    };

    var instructionLinks = function(instruction, i) {
      if (instruction.next[1] !== undefined) { // Conditional instruction
        var links = "";

        if (instruction.next[0] !== -1) // Valid address
          links = "i" + i + "(no)->i" + instruction.next[0] + "\n";
        if (instruction.next[1] !== -1) // Valid address
          links += "i" + i + "(yes, right)->i" + instruction.next[1] + "\n";

        return links
      } else {
        if (instruction.next[0] !== -1) // Valid address
          return "i" + i + "->i" + instruction.next[0] + "\n";
        else
          return "";
      }
    }

    var lastAddress = instructions.length + idtLength, instruction = '';

    if (instructions.length) // Start and end symbols
      links += "st->i" + idtLength + "\ni" + (lastAddress - 1) + "->e\n";

    for (var i = idtLength; i < lastAddress; i++) {
      instruction = instructions[i - idtLength];

      // Check for valid addresses
      if (instruction.next[0] >= lastAddress)
        instruction.next[0] = -1;

      if (instruction.next[1] >= lastAddress)
        instruction.next[1] = -1;

      definitions += instructionDefinition(instruction, i);
      links += instructionLinks(instruction, i);
    }

    return definitions + links;
  }

  var showAssembly = function(data) {
    var instructions = data.instructions;
    var idt = data.idt;
    var prog = [new Comment('Generated assembly, see:'),
                new Comment('    http://chriscummins.cc/disassembler'),
                new Comment(''),
                new BlankLine()];
    var string = '';

    if (idt.length) { // Show interrupt table label
      prog.push(new Section('data'));
      prog.push(new BlankLine());

      idt[0].label = new Label('interrupt_vectors');
      idt.forEach(function(e) {
        prog.push(e);
      });

      prog.push(new BlankLine());
    }

    prog.push(new Section('text'));
    prog.push(new BlankLine());

    if (instructions.length) // Set special "start" label
      instructions[0].label = new Label('start');

    instructions.forEach(function(e) {
      prog.push(e);
    });

    // Generate label cross references
    prog.forEach(function(e) {
      try {
        e.toString(instructions);
      } catch (err) {
        addError("At address " + e.addressHex +
                 ": Branch address out of bounds!")
      }
    });

    prog.push(new BlankLine());
    prog.push(new Comment('End of program code'))

    // Display table
    prog.forEach(function(e) {
      try {
        addInstruction(e, instructions);
      } catch (e) {}
    });
  };

  var _diagram; // The flowchart

  // Display an array of instructions
  var show = function(data) {

    var instructions = data.instructions;
    var idt = data.idt;

    showAssembly(data);

    if (idt.length || instructions.length)
      $('#code-output').show();
    else
      $('#code-output').hide();

    if (!programContainsRoutines && instructions.length) { // Only draw the flowchart if we can
      $('#diagram').show();

      if (_diagram)
        _diagram.clean();

      _diagram = flowchart.parse(instructionsToChart(instructions));
      _diagram.drawSVG('diagram');
    } else {
      $('#diagram').hide();
    }
  };

  var addError = function(msg) {
    $errors.append("
" + msg +
                   "×
");
  };

  var addWarning = function(msg) {
    $warnings.append("
" + msg +
                     "×
");
  };

  var addInstruction = function(instruction, instructions) {
    var addRow = function(address, instruction, caption) {
      $output.append('

' + address +
                     '

' +
                     instruction + '

');
    };

    var address = instruction.address === undefined ?
      '' : instruction.addressHex;
    var caption = instruction.desc === undefined ? '' : instruction.desc;
    var lines = instruction.toString(instructions).split('\n');

    if (lines.length > 1) { // Instruction contains label
      addRow('', lines[0], '');
      addRow(address, lines[1], caption);
    } else {
      addRow(address, lines[0], caption);
    };
  };

  var refresh = function() { // Refresh display
    $errors.html('');
    $warnings.html('');
    $output.html('');
    _labelCounter = 0;
    _routineCounter = 0;
    _handlerCounter = 0;
    programContainsRoutines = false;

    show(decode($code.val().split("\n")));
  };

  // Update as the user types
  $code.bind('input propertychange', function() {
    refresh();
  });

  $('#idt-enable').change(function() {
    idtLength = parseInt($('#idt-enable option:selected').val());
    refresh();
  });

}).call(Disassembler);
<|endoftext|>


<commit_before>// dom.postable

(function(window) {
    "use strict";

    var dom     = window.dom;
    var Fn      = window.Fn;
    var get     = Fn.get;

    // Define

    var matches = dom.matches('.postable, [postable]');

    // Functions
    dom.event('submit', document)
        .filter(function(event){
            return matches(event.target);
        })
        .tap(dom.preventDefault)
        .map(get('target'))
        .each(function(node){
            var action = node.getAttribute('action');
            var post_data = new FormData(node);
            console.log(post_data);
            axios.post(action, post_data)
            .then(function(response){
                if(response.status < 300) {
                    dom.events.trigger(node, 'dom-posted', {detail: response.data});
                } else {
                    var error = new Error(response.statusText);
                    error.response = response;
                    dom.events.trigger(node, 'dom-error', {detail: error})
                }
            })
            .catch(function(error_response){
                dom.events.trigger(node, 'dom-error', {detail: error_response})
            });
        });

})(this);
<commit_msg>Format<commit_after>// dom.postable

(function(window) {
    "use strict";

    var dom     = window.dom;
    var Fn      = window.Fn;
    var get     = Fn.get;

    // Define

    var matches = dom.matches('.postable, [postable]');

    // Functions
    dom.event('submit', document)
        .filter(function(event){
            return matches(event.target);
        })
        .tap(dom.preventDefault)
        .map(get('target'))
        .each(function(node){
            var action = node.getAttribute('action');
            var post_data = new FormData(node);
            console.log(post_data);

            axios
            .post(action, post_data)
            .then(function(response){
                if(response.status < 300) {
                    dom.events.trigger(node, 'dom-posted', {detail: response.data});
                } else {
                    var error = new Error(response.statusText);
                    error.response = response;
                    dom.events.trigger(node, 'dom-error', {detail: error})
                }
            })
            .catch(function(error_response){
                dom.events.trigger(node, 'dom-error', {detail: error_response})
            });
        });

})(this);
<|endoftext|>


<commit_before>var fetch   = require("node-fetch");
var cheerio = require("cheerio");

// subfunction
var attr = function attr(value) {
    var isMember = typeof value !== "function";

    return {
        value: value,
        writable: isMember,
        enumerable: isMember,
        configurable: false
    }
};

var str2num = function str2num(str) {
    return parseInt(str.split(",").join(""));
};

var isNatural = function isNatural(num) {
    return typeof num === "number" && num > 0 && num % 1 === 0;
};

var isWord = function isWord(str) {
    return typeof str === "string" && str.length > 0;
};

// Character.create
var create = function create() {
    var isValidProperty = function isValidProperty(obj) {
        return typeof obj === "object"  &&
                isNatural(obj.LV)       &&
                isNatural(obj.HP)       &&
                isNatural(obj.ATK)      &&
                isNatural(obj.RCV);
    };

    var Character = function Character() {};
    var instance = new Character();

    Object.defineProperties(instance, {
        no:      attr(0),
        name:    attr(null),
        type:    attr(null),
        classes: attr([]),
        star:    attr(0),
        cost:    attr(0),
        combo:   attr(0),
        min:     attr({ LV: 0, HP: 0, ATK: 0, RCV: 0 }),
        max:     attr({ LV: 0, HP: 0, ATK: 0, RCV: 0 }),

        setNo: attr(function setNo(no) {
            if (!isNatural(no)) {
                throw new Error("no '" + no + "' is invalid");
            }

            instance.no = no;
            return instance;
        }),

        setName: attr(function setNo(name) {
            if (!isWord(name)) {
                throw new Error("name '" + name + "' is invalid");
            }

            instance.name = name;
            return instance;
        }),

        setType: attr(function setType(type) {
            if (!isWord(type)) {
                throw new Error("type '" + type + "' is invalid");
            }

            instance.type = type;
            return instance;
        }),

        addClass: attr(function addClass(classes) {
            if (!isWord(classes)) {
                throw new Error("classes '" + classes + "' is invalid");
            }

            // ignore classes "-"
            if (classes !== "-") {
                instance.classes.push(classes);
            }
            return instance;
        }),

        setStar: attr(function setStar(star) {
            if (!isNatural(star)) {
                throw new Error("star '" + star + "' is invalid");
            }

            instance.star = star;
            return instance;
        }),

        setCost: attr(function setCost(cost) {
            if (!isNatural(cost)) {
                throw new Error("cost '" + cost + "' is invalid");
            }

            instance.cost = cost;
            return instance;
        }),

        setCombo: attr(function setCombo(combo) {
            if (!isNatural(combo)) {
                throw new Error("combo '" + combo + "' is invalid");
            }

            instance.combo = combo;
            return instance;
        }),

        setMin: attr(function setMin(obj) {
            if (!isValidProperty(obj)) {
                throw new Error("property '" + property + "' is invalid");
            }

            instance.min = {
                LV:  obj.LV,
                HP:  obj.HP,
                ATK: obj.ATK,
                RCV: obj.RCV
            };
            return instance;
        }),

        setMax: attr(function setMax(obj) {
            if (!isValidProperty(obj)) {
                throw new Error("property '" + property + "' is invalid");
            }

            instance.max = {
                LV:  obj.LV,
                HP:  obj.HP,
                ATK: obj.ATK,
                RCV: obj.RCV
            };
            return instance;
        })
    });

    return instance;
};

// fetch character data from Japan official website (http://onepiece-treasurecruise.com)
var fetchFromJapan = function fetchFromJapan(number, response) {

    var cb = typeof response === "function" ? response : function() {};
    if (!isNatural(number)) {
        cb(number, new Error("number '" + number + "' is invalid"));
        return;
    }

    fetch("http://onepiece-treasurecruise.com/c-" + number, {
        method: "GET",
        timeout: 30 * 1000
    })

    .then(function(res) {
        return res.text();
    })

    .then(function(html) {
        var $ = cheerio.load(html);
        var info1 = $('#left table').eq(1).find("td");
        var info2 = $('#left table').eq(2).find("td");
        var min   = $('#left table').eq(3).find("tr").eq(1).find("td");
        var max   = $('#left table').eq(3).find("tr").eq(2).find("td");

        var character = create().setNo(number)
                                .setName($("#entry h1").text())
                                .setType(info1.eq(0).text())
                                .addClass(info1.eq(1).text())
                                .addClass(info1.eq(2).text())
                                .setStar(str2num(info1.eq(3).text()))
                                .setCost(str2num(info1.eq(4).text()))
                                .setCombo(str2num(info2.eq(1).text()))
                                .setMin({
                                    LV:  str2num(min.eq(1).text()),
                                    HP:  str2num(min.eq(2).text()),
                                    ATK: str2num(min.eq(3).text()),
                                    RCV: str2num(min.eq(4).text())
                                })
                                .setMax({
                                    LV:  str2num(max.eq(1).text()),
                                    HP:  str2num(max.eq(2).text()),
                                    ATK: str2num(max.eq(3).text()),
                                    RCV: str2num(max.eq(4).text())
                                });

        cb(number, null, character);
    })

    .catch(function(error) {
        cb(number, error);
    });
};

// fetch character data from Taiwan official website (http://line-optc.com/tw)
var fetchFromTaiwan = function fetchFromTaiwan(number, response) {

    var cb = typeof response === "function" ? response : function() {};
    if (!isNatural(number)) {
        cb(number, new Error("number '" + number + "' is invalid"));
        return;
    }

    fetch("http://line-optc.com/tw/c-" + number, {
        method: "GET",
        timeout: 30 * 1000
    })

    .then(function(res) {
        return res.text();
    })

    .then(function(html) {
        var $ = cheerio.load(html);
        var info = $('#left table').eq(1).find("td");
        var min  = $('#left table').eq(2).find("tr").eq(1).find("td");
        var max  = $('#left table').eq(2).find("tr").eq(2).find("td");

        var character = create().setNo(number)
                                .setName($("#entry h1").text())
                                .setType(info.eq(0).text())
                                .addClass(info.eq(1).text())
                                .setStar(str2num(info.eq(2).text()))
                                .setCost(str2num(info.eq(3).text()))
                                .setCombo(str2num(info.eq(4).text()))
                                .setMin({
                                    LV:  str2num(min.eq(1).text()),
                                    HP:  str2num(min.eq(2).text()),
                                    ATK: str2num(min.eq(3).text()),
                                    RCV: str2num(min.eq(4).text())
                                })
                                .setMax({
                                    LV:  str2num(max.eq(1).text()),
                                    HP:  str2num(max.eq(2).text()),
                                    ATK: str2num(max.eq(3).text()),
                                    RCV: str2num(max.eq(4).text())
                                });

        cb(number, null, character);
    })

    .catch(function(error) {
        cb(number, error);
    });
};

// export
module.exports = {
    create: create,
    fetch: fetchFromJapan
};
<commit_msg>[refactro] rename function 'create' to 'createCharacter'<commit_after>var fetch   = require("node-fetch");
var cheerio = require("cheerio");

// subfunction
var attr = function attr(value) {
    var isMember = typeof value !== "function";

    return {
        value: value,
        writable: isMember,
        enumerable: isMember,
        configurable: false
    }
};

var str2num = function str2num(str) {
    return parseInt(str.split(",").join(""));
};

var isNatural = function isNatural(num) {
    return typeof num === "number" && num > 0 && num % 1 === 0;
};

var isWord = function isWord(str) {
    return typeof str === "string" && str.length > 0;
};

// Character.create
var createCharacter = function createCharacter() {
    var isValidProperty = function isValidProperty(obj) {
        return typeof obj === "object"  &&
                isNatural(obj.LV)       &&
                isNatural(obj.HP)       &&
                isNatural(obj.ATK)      &&
                isNatural(obj.RCV);
    };

    var Character = function Character() {};
    var instance = new Character();

    Object.defineProperties(instance, {
        no:      attr(0),
        name:    attr(null),
        type:    attr(null),
        classes: attr([]),
        star:    attr(0),
        cost:    attr(0),
        combo:   attr(0),
        min:     attr({ LV: 0, HP: 0, ATK: 0, RCV: 0 }),
        max:     attr({ LV: 0, HP: 0, ATK: 0, RCV: 0 }),

        setNo: attr(function setNo(no) {
            if (!isNatural(no)) {
                throw new Error("no '" + no + "' is invalid");
            }

            instance.no = no;
            return instance;
        }),

        setName: attr(function setNo(name) {
            if (!isWord(name)) {
                throw new Error("name '" + name + "' is invalid");
            }

            instance.name = name;
            return instance;
        }),

        setType: attr(function setType(type) {
            if (!isWord(type)) {
                throw new Error("type '" + type + "' is invalid");
            }

            instance.type = type;
            return instance;
        }),

        addClass: attr(function addClass(classes) {
            if (!isWord(classes)) {
                throw new Error("classes '" + classes + "' is invalid");
            }

            // ignore classes "-"
            if (classes !== "-") {
                instance.classes.push(classes);
            }
            return instance;
        }),

        setStar: attr(function setStar(star) {
            if (!isNatural(star)) {
                throw new Error("star '" + star + "' is invalid");
            }

            instance.star = star;
            return instance;
        }),

        setCost: attr(function setCost(cost) {
            if (!isNatural(cost)) {
                throw new Error("cost '" + cost + "' is invalid");
            }

            instance.cost = cost;
            return instance;
        }),

        setCombo: attr(function setCombo(combo) {
            if (!isNatural(combo)) {
                throw new Error("combo '" + combo + "' is invalid");
            }

            instance.combo = combo;
            return instance;
        }),

        setMin: attr(function setMin(obj) {
            if (!isValidProperty(obj)) {
                throw new Error("property '" + property + "' is invalid");
            }

            instance.min = {
                LV:  obj.LV,
                HP:  obj.HP,
                ATK: obj.ATK,
                RCV: obj.RCV
            };
            return instance;
        }),

        setMax: attr(function setMax(obj) {
            if (!isValidProperty(obj)) {
                throw new Error("property '" + property + "' is invalid");
            }

            instance.max = {
                LV:  obj.LV,
                HP:  obj.HP,
                ATK: obj.ATK,
                RCV: obj.RCV
            };
            return instance;
        })
    });

    return instance;
};

// fetch character data from Japan official website (http://onepiece-treasurecruise.com)
var fetchFromJapan = function fetchFromJapan(number, response) {

    var cb = typeof response === "function" ? response : function() {};
    if (!isNatural(number)) {
        cb(number, new Error("number '" + number + "' is invalid"));
        return;
    }

    fetch("http://onepiece-treasurecruise.com/c-" + number, {
        method: "GET",
        timeout: 30 * 1000
    })

    .then(function(res) {
        return res.text();
    })

    .then(function(html) {
        var $ = cheerio.load(html);
        var info1 = $('#left table').eq(1).find("td");
        var info2 = $('#left table').eq(2).find("td");
        var min   = $('#left table').eq(3).find("tr").eq(1).find("td");
        var max   = $('#left table').eq(3).find("tr").eq(2).find("td");

        var character = createCharacter()
                        .setNo(number)
                        .setName($("#entry h1").text())
                        .setType(info1.eq(0).text())
                        .addClass(info1.eq(1).text())
                        .addClass(info1.eq(2).text())
                        .setStar(str2num(info1.eq(3).text()))
                        .setCost(str2num(info1.eq(4).text()))
                        .setCombo(str2num(info2.eq(1).text()))
                        .setMin({
                            LV:  str2num(min.eq(1).text()),
                            HP:  str2num(min.eq(2).text()),
                            ATK: str2num(min.eq(3).text()),
                            RCV: str2num(min.eq(4).text())
                        })
                        .setMax({
                            LV:  str2num(max.eq(1).text()),
                            HP:  str2num(max.eq(2).text()),
                            ATK: str2num(max.eq(3).text()),
                            RCV: str2num(max.eq(4).text())
                        });

        cb(number, null, character);
    })

    .catch(function(error) {
        cb(number, error);
    });
};

// fetch character data from Taiwan official website (http://line-optc.com/tw)
var fetchFromTaiwan = function fetchFromTaiwan(number, response) {

    var cb = typeof response === "function" ? response : function() {};
    if (!isNatural(number)) {
        cb(number, new Error("number '" + number + "' is invalid"));
        return;
    }

    fetch("http://line-optc.com/tw/c-" + number, {
        method: "GET",
        timeout: 30 * 1000
    })

    .then(function(res) {
        return res.text();
    })

    .then(function(html) {
        var $ = cheerio.load(html);
        var info = $('#left table').eq(1).find("td");
        var min  = $('#left table').eq(2).find("tr").eq(1).find("td");
        var max  = $('#left table').eq(2).find("tr").eq(2).find("td");

        var character = createCharacter()
                            .setNo(number)
                            .setName($("#entry h1").text())
                            .setType(info.eq(0).text())
                            .addClass(info.eq(1).text())
                            .setStar(str2num(info.eq(2).text()))
                            .setCost(str2num(info.eq(3).text()))
                            .setCombo(str2num(info.eq(4).text()))
                            .setMin({
                                LV:  str2num(min.eq(1).text()),
                                HP:  str2num(min.eq(2).text()),
                                ATK: str2num(min.eq(3).text()),
                                RCV: str2num(min.eq(4).text())
                            })
                            .setMax({
                                LV:  str2num(max.eq(1).text()),
                                HP:  str2num(max.eq(2).text()),
                                ATK: str2num(max.eq(3).text()),
                                RCV: str2num(max.eq(4).text())
                            });

        cb(number, null, character);
    })

    .catch(function(error) {
        cb(number, error);
    });
};

// export
module.exports = {
    create: createCharacter,
    fetch: fetchFromJapan
};
<|endoftext|>


<commit_before>/**
 * jQuery Slidy - A Transition Plugin - http://wbotelhos.com/slidy
 * ---------------------------------------------------------------------------------
 *
 * jQuery Slidy is a plugin that generates a customizable transitions automatically.
 *
 * Licensed under The MIT License
 *
 * @version         0.2.0
 * @since           11.16.2010
 * @author          Washington Botelho dos Santos
 * @documentation   wbotelhos.com/slidy
 * @twitter         twitter.com/wbotelhos
 * @license         opensource.org/licenses/mit-license.php MIT
 * @package         jQuery Plugins
 *
 * Usage with default values:
 * ---------------------------------------------------------------------------------
 * $('#default').slidy();
 *
 *

 *
 *
 *
 *

 *
 */

;(function($) {

	$.fn.slidy = function(settings) {

		if (this.length == 0) {
			debug('Selector invalid or missing!');
			return;
		} else if (this.length > 1) {
			return this.each(function() {
				$.fn.slidy.apply($(this), [settings]);
			});
		}

		var opt			= $.extend({}, $.fn.slidy.defaults, settings),
			$this		= $(this),
			id			= this.attr('id'),
			elements	= $this.children(opt.children),
			quantity	= elements.length,
			images		= (opt.children == 'img') ? elements : elements.find('img'),
			timer		= 0,
			isAnimate	= false;

		if (id === undefined) {
			id = 'slidy-' + $this.index();
			$this.attr('id', id);
		}

		$this
		.data('options', opt)
		.css({
			'cursor':	opt.cursor,
			'height':	opt.height + 'px',
			'overflow':	'hidden',
			'position':	'relative',
			'width':	opt.width + 'px'
		});

		elements.each(function(i) {
			$(this)
			.css({ 'position': 'absolute', 'z-index': quantity - i })
			.attr('id', $this.attr('id') + '-' + (i + 1));
		});

		images.attr({ height: opt.height, width: opt.width }).css('border', '0');

		if (opt.children == 'a' && opt.target != '') {
			elements.attr('target',	opt.target);
		}

		elements.hide().first().show();

		go(elements, opt, 0);

		var stop = function() {
			var target = $(this),
				index,
				last;

			clearTimeout(timer);

			if (target.is('li')) {
				index	= target.index();
				last	= target.parent().children('.slidy-link-selected').index();
			} else {
				index	= $this.next('ul').children('.slidy-link-selected').index();
				last	= index;
			}

			if (index != last) {
				target.addClass('slidy-link-selected')
					.parent()
						.children()
							.eq(last).removeClass('slidy-link-selected');

				change(elements, opt, index, last);
			}
		}, start = function() {
			var index	= $this.next('ul').children('.slidy-link-selected').index(),
				isBanner; // Avoid hover the same li again.

			// Is not used element.index() because the delay effect can be select another is not the same of cursor over.
			if (!$(this).is('li')) {
				isBanner = true;
			}

			go(elements, opt, index, isBanner);
		};

		if (opt.menu) {
			var menu	= '',
				target	= (opt.target != '') ? 'target="' + opt.target + '"' : '',
				parent,
				img;

			images.each(function() {
				img		= $(this);
				parent	= img.parent(opt.children);

				menu += '
' + img.attr('title') + '
';
			});

			var $menu = $('
', {
							id:			id + '-slidy-menu',
							'class':	'slidy-menu',
							html:		menu
						});

			$this.after($menu);

			var	space	= parseInt((opt.width / quantity) + (quantity - 1)),
				diff	= opt.width - (space * quantity),
				links	= $menu.children('li');

			links
			.css('width', space)
			.hover(stop, start)
			.mousemove(stop) // To fix the delay of the effect and moviment of cursor. Avoid mouseout and mouseover again to change. Overhead?
				.first().addClass('slidy-link-selected')
			.end()
				.last().css({ 'border-right': '0', 'width': (space + diff) - (quantity - 1) });
		}

		if (opt.pause) {
			$this.hover(stop, start);
		}

		function go(elements, opt, index, isBanner) {
			change(elements, opt, index, index - 1);

			if (isBanner == undefined) {
				selectMenu(index);
			}

			index = (index < quantity - 1) ? index + 1 : 0;

			timer =	setTimeout(function() {
						go(elements, opt, index);
					}, opt.time);
		};

		function change(elements, opt, index, last) {
			if (!isAnimate) {
				isAnimate = true;

				if (opt.animation == 'fade') {
					elements
						.eq(last).fadeOut(opt.speed)
					.end()
						.eq(index).fadeIn(opt.speed, function() {
							selectMenu(index);
							isAnimate = false;
						});
				} else if (opt.animation == 'slide') {
					elements
					.css('z-index', 0)
						.eq(index)
						.css('z-index', quantity)
						.slideDown(opt.speed, function() {
							elements.eq(last).hide();
							selectMenu(index);
							isAnimate = false;
						});
				} else {
					elements
						.eq(last).hide()
					.end()
						.eq(index).show();
					isAnimate = false;
				}
			}
		};

		function selectMenu(index) {
			$this
				.next('ul.slidy-menu')
					.children().removeClass('slidy-link-selected')
						.eq(index).addClass('slidy-link-selected');
		};

		return $this;
	};

	function debug(message) {
		if (window.console && window.console.log) {
			window.console.log(message);
		}
	};

	$.fn.slidy.defaults = {
		animation:	'normal',
		children:	'img',
		cursor:		'default',
		height:		200,
		menu:		false,
		pause:		false,
		speed:		600,
		target:		'',
		time:		3600,
		width:		500
	};

})(jQuery);<commit_msg>Avoided try change menu when it not exists.<commit_after>/**
 * jQuery Slidy - A Transition Plugin - http://wbotelhos.com/slidy
 * ---------------------------------------------------------------------------------
 *
 * jQuery Slidy is a plugin that generates a customizable transitions automatically.
 *
 * Licensed under The MIT License
 *
 * @version         0.2.0
 * @since           11.16.2010
 * @author          Washington Botelho dos Santos
 * @documentation   wbotelhos.com/slidy
 * @twitter         twitter.com/wbotelhos
 * @license         opensource.org/licenses/mit-license.php MIT
 * @package         jQuery Plugins
 *
 * Usage with default values:
 * ---------------------------------------------------------------------------------
 * $('#default').slidy();
 *
 *

 *
 *
 *
 *

 *
 */

;(function($) {

	$.fn.slidy = function(settings) {

		if (this.length == 0) {
			debug('Selector invalid or missing!');
			return;
		} else if (this.length > 1) {
			return this.each(function() {
				$.fn.slidy.apply($(this), [settings]);
			});
		}

		var opt			= $.extend({}, $.fn.slidy.defaults, settings),
			$this		= $(this),
			id			= this.attr('id'),
			elements	= $this.children(opt.children),
			quantity	= elements.length,
			images		= (opt.children == 'img') ? elements : elements.find('img'),
			timer		= 0,
			isAnimate	= false;

		if (id === undefined) {
			id = 'slidy-' + $this.index();
			$this.attr('id', id);
		}

		$this
		.data('options', opt)
		.css({
			'cursor':	opt.cursor,
			'height':	opt.height + 'px',
			'overflow':	'hidden',
			'position':	'relative',
			'width':	opt.width + 'px'
		});

		elements.each(function(i) {
			$(this)
			.css({ 'position': 'absolute', 'z-index': quantity - i })
			.attr('id', $this.attr('id') + '-' + (i + 1));
		});

		images.attr({ height: opt.height, width: opt.width }).css('border', '0');

		if (opt.children == 'a' && opt.target != '') {
			elements.attr('target',	opt.target);
		}

		elements.hide().first().show();

		go(elements, opt, 0);

		var stop = function() {
			var target = $(this),
				index,
				last;

			clearTimeout(timer);

			if (target.is('li')) {
				index	= target.index();
				last	= target.parent().children('.slidy-link-selected').index();
			} else {
				index	= $this.next('ul').children('.slidy-link-selected').index();
				last	= index;
			}

			if (index != last) {
				target.addClass('slidy-link-selected')
					.parent()
						.children()
							.eq(last).removeClass('slidy-link-selected');

				change(elements, opt, index, last);
			}
		}, start = function() {
			var index	= $this.next('ul').children('.slidy-link-selected').index(),
				isBanner; // Avoid hover the same li again.

			// Is not used element.index() because the delay effect can be select another is not the same of cursor over.
			if (!$(this).is('li')) {
				isBanner = true;
			}

			go(elements, opt, index, isBanner);
		};

		if (opt.menu) {
			var menu	= '',
				target	= (opt.target != '') ? 'target="' + opt.target + '"' : '',
				parent,
				img;

			images.each(function() {
				img		= $(this);
				parent	= img.parent(opt.children);

				menu += '
' + img.attr('title') + '
';
			});

			var $menu = $('
', {
							id:			id + '-slidy-menu',
							'class':	'slidy-menu',
							html:		menu
						});

			$this.after($menu);

			var	space	= parseInt((opt.width / quantity) + (quantity - 1)),
				diff	= opt.width - (space * quantity),
				links	= $menu.children('li');

			links
			.css('width', space)
			.hover(stop, start)
			.mousemove(stop) // To fix the delay of the effect and moviment of cursor. Avoid mouseout and mouseover again to change. Overhead?
				.first().addClass('slidy-link-selected')
			.end()
				.last().css({ 'border-right': '0', 'width': (space + diff) - (quantity - 1) });
		}

		if (opt.pause) {
			$this.hover(stop, start);
		}

		function go(elements, opt, index, isBanner) {
			change(elements, opt, index, index - 1);

			if (isBanner == undefined) {
				selectMenu(index);
			}

			index = (index < quantity - 1) ? index + 1 : 0;

			timer =	setTimeout(function() {
						go(elements, opt, index);
					}, opt.time);
		};

		function change(elements, opt, index, last) {
			if (!isAnimate) {
				isAnimate = true;

				if (opt.animation == 'fade') {
					elements
						.eq(last).fadeOut(opt.speed)
					.end()
						.eq(index).fadeIn(opt.speed, function() {
							selectMenu(index);
							isAnimate = false;
						});
				} else if (opt.animation == 'slide') {
					elements
					.css('z-index', 0)
						.eq(index)
						.css('z-index', quantity)
						.slideDown(opt.speed, function() {
							elements.eq(last).hide();
							selectMenu(index);
							isAnimate = false;
						});
				} else {
					elements
						.eq(last).hide()
					.end()
						.eq(index).show();
					isAnimate = false;
				}
			}
		};

		function selectMenu(index) {
			if (opt.menu) {
				$this
					.next('ul.slidy-menu')
						.children().removeClass('slidy-link-selected')
							.eq(index).addClass('slidy-link-selected');
			}
		};

		return $this;
	};

	function debug(message) {
		if (window.console && window.console.log) {
			window.console.log(message);
		}
	};

	$.fn.slidy.defaults = {
		animation:	'normal',
		children:	'img',
		cursor:		'default',
		height:		200,
		menu:		false,
		pause:		false,
		speed:		600,
		target:		'',
		time:		3600,
		width:		500
	};

})(jQuery);<|endoftext|>


<commit_before>'use strict';

function checkAll(){
    var checkboxes = document.getElementsByTagName('input');
    for(var checkbox in checkboxes){
        if(checkboxes[checkbox].type === 'checkbox'){
            checkboxes[checkbox].checked = true;
        }
    }
}

function check_checkbox(id){
    if(!document.getElementById(id)){
        return;
    }

    document.getElementById('checkbox-' + id).checked =
      !document.getElementById('checkbox-' + id).checked;
}

function clearAll(){
    if(!window.confirm('window.localStorage.clear()?')){
        return;
    }

    window.localStorage.clear();
    refresh();
}

function headers(){
    document.getElementById('result').innerHTML =
      '
'
        + 'Key <input onclick=refresh() type=button value="Refresh [R]">'
          + '<input onclick=checkAll() type=button value=checkAll()>'
          + '<input onclick=removeChecked() type=button value=removeChecked()>'
        + '<input onclick=removeAll() type=button value=removeAll()>'
          + '<input onclick=clearAll() type=button value=window.localStorage.clear()>'
          + ' Value'
      + document.getElementById('result').innerHTML;
}

function refresh(){
    var output = '';

    for(var key in window.localStorage){
        output += '
<input disabled id="checkbox-'
          + key
          + '" type=checkbox><input onclick="removeItem(\'' + key + '\', this)" type=button value=X> '
          + key
          + '<textarea>'
          + window.localStorage.getItem(key)
          + '</textarea>';
    }

    document.getElementById('result').innerHTML = output;

    headers();
}

function removeAll(){
    if(!window.confirm('removeAll()?')){
        return;
    }

    for(var key in window.localStorage){
        window.localStorage.removeItem(key);
    }

    document.getElementById('result').innerHTML = '';
    headers();
}

function removeChecked(){
    if(!window.confirm('removeChecked()?')){
        return;
    }

    for(var key in window.localStorage){
        if(document.getElementById('checkbox-' + key).checked){
            window.localStorage.removeItem(key);
        }
    }

    refresh();
}

function removeItem(key, element){
    if(!window.confirm('Remove ' + key + '?')){
        return;
    }

    window.localStorage.removeItem(key);
    element.parentElement.parentElement.remove();
}

function repo_init(){
    core_events_bind({
      'keybinds': {
        82: {
          'todo': refresh,
        },
      },
    });

    refresh();
};
<commit_msg>added core_repo_init() usage<commit_after>'use strict';

function checkAll(){
    var checkboxes = document.getElementsByTagName('input');
    for(var checkbox in checkboxes){
        if(checkboxes[checkbox].type === 'checkbox'){
            checkboxes[checkbox].checked = true;
        }
    }
}

function check_checkbox(id){
    if(!document.getElementById(id)){
        return;
    }

    document.getElementById('checkbox-' + id).checked =
      !document.getElementById('checkbox-' + id).checked;
}

function clearAll(){
    if(!window.confirm('window.localStorage.clear()?')){
        return;
    }

    window.localStorage.clear();
    refresh();
}

function headers(){
    document.getElementById('result').innerHTML =
      '
'
        + 'Key <input onclick=refresh() type=button value="Refresh [R]">'
          + '<input onclick=checkAll() type=button value=checkAll()>'
          + '<input onclick=removeChecked() type=button value=removeChecked()>'
        + '<input onclick=removeAll() type=button value=removeAll()>'
          + '<input onclick=clearAll() type=button value=window.localStorage.clear()>'
          + ' Value'
      + document.getElementById('result').innerHTML;
}

function refresh(){
    var output = '';

    for(var key in window.localStorage){
        output += '
<input disabled id="checkbox-'
          + key
          + '" type=checkbox><input onclick="removeItem(\'' + key + '\', this)" type=button value=X> '
          + key
          + '<textarea>'
          + window.localStorage.getItem(key)
          + '</textarea>';
    }

    document.getElementById('result').innerHTML = output;

    headers();
}

function removeAll(){
    if(!window.confirm('removeAll()?')){
        return;
    }

    for(var key in window.localStorage){
        window.localStorage.removeItem(key);
    }

    document.getElementById('result').innerHTML = '';
    headers();
}

function removeChecked(){
    if(!window.confirm('removeChecked()?')){
        return;
    }

    for(var key in window.localStorage){
        if(document.getElementById('checkbox-' + key).checked){
            window.localStorage.removeItem(key);
        }
    }

    refresh();
}

function removeItem(key, element){
    if(!window.confirm('Remove ' + key + '?')){
        return;
    }

    window.localStorage.removeItem(key);
    element.parentElement.parentElement.remove();
}

function repo_init(){
    core_repo_init({
      'title': 'LocalStorage.htm',
    });
    core_events_bind({
      'keybinds': {
        82: {
          'todo': refresh,
        },
      },
    });

    refresh();
};
<|endoftext|>


<commit_before>class MatrixChart {
    constructor(parentElement, svgId, options = {}) {
        this.data = {};
        this.options = {
            backgroundColor: 'white',
            statusColorMap: { // background color
                0: 'green',
                1: 'red',
            },
            statusClassMap: { // css class
            },
            defaultStatus: 0,
            transpose: false,
            strokeWidth: 1,
            squareSize: 7,
            xAxisAlign: 'left',
            xAxisName: false,
            yAxisName: false,
            xAxisLabelNameGetter: (columnIndex) => {
                return false;
            },
            mouseOverCallback: () => {
            },
            mouseOutCallback: () => {
            },
            mouseClickPixelCallback: () => {
            },
            mouseDblClickPixelCallback: () => {
            },
            mouseOverPixelCallback: () => {
            },
            mouseOutPixelCallback: () => {
            },
            mouseXAxisClickCallback: () => {
            },
            mouseYAxisClickCallback: () => {
            }
        };
        this.settings = {
            xShift: this.options.squareSize / 2,
            yShift: this.options.squareSize / 2,
        };

        this.parentElement = __.cel('span', {}, parentElement);
        this.options = __.merge(this.options, options);
        this.shadow = this.parentElement.attachShadow({mode: 'open'});
        this.svg = this._createSVGRootElement(svgId);
        __.ach(this.shadow, this.svg);
    }

    /**
     *
     * data format:
     * ```
     * {
     * rows: [
     *          0: {
     *              id: ..,
     *              name: ...,
     *              series: [ // if not empty populate with non-default pixel statuses
     *                  53: 4,
     *                  99: 1,
     *                  103: {state: 2, text: '....'},
     *              ]
     *          }
     *      ],
     *      // columns IS OPTIONAL
     * columns: [
     *     ....
     *     53: {
     *          id: ...,
     *          name: ...
     *     }
     *  ],
     * customData: { // optional custom data
     *
     *  }
     * }
     *```
     * @param data
     */
    draw(data) {
        this.data = data;
        this._prepareCanvas();
        this._attachGlobalListeners();
        this._drawRows();
        this._drawLabels();
    }

    setOptions(options) {
        this.options = options;
    }

    getOptions() {
        return this.options;
    }

    getCustomData() {
        return this.data.customData || {};
    }

    getSvg() {
        return this.svg;
    }

    _attachGlobalListeners() {
        this.svg.addEventListener('mouseover', this.options.mouseOverCallback);
        this.svg.addEventListener('mouseout', this.options.mouseOutCallback);
    }

    _getSvgBox() {
        return this.svg.getBoundingClientRect();
    }

    _createSVGRootElement(id) {
        const root = this._createSVGElement('svg', {id: `svg-${id}`});
        if (this.options.hasOwnProperty('externalCss')) {
            __.cel('link', {
                rel: 'stylesheet',
                href: this.options.externalCss
            }, this.shadow);
        }
        return root;
    }

    _createSVGElement(tag, attrs = {}, title = false) {
        let el = document.createElementNS('http://www.w3.org/2000/svg', tag);
        __.attrs(el, attrs);
        if (!title) return el;
        el.innerHTML = `<title>${title}</title>`;
        return el;
    }

    _createPixel(pixelInfo, pixelX, pixelY) {
        const zoom = this.options.squareSize;
        let state = pixelInfo.hasOwnProperty('state') ? pixelInfo.state : pixelInfo;
        state = state === "undefined" ? this.options.defaultStatus : state;

        let x = this._getXShift() + pixelX * zoom;
        if (this.options.xAxisAlign === 'right') {
            x = this._getSvgBox().width - pixelX * zoom - 1.5 * zoom;
        }
        let rect = this._createSVGElement('rect', {
            width: zoom,
            height: zoom,
            x,
            y: pixelY * zoom + this.settings.yShift,
        });
        const cssClass = this.options.statusClassMap[state] || false;
        if (cssClass) {
            rect.classList.add(cssClass);
        } else {
            rect.style.fill = this.options.statusColorMap[state] || this.options.statusColorMap[this.options.defaultStatus];
        }
        const name = this.data.hasOwnProperty('columns') ? this.data.columns[pixelX]['name'] : "undefined",
            id = this.data.hasOwnProperty('columns') ? this.data.columns[pixelX]['id'] : "undefined",
            title = pixelInfo.hasOwnProperty('title') ? encodeURIComponent(pixelInfo['title']) : "undefined",
            desc = pixelInfo['text'] || "undefined";
        __.props(rect, {
            style: {
                strokeWidth: `${this.options.strokeWidth}px`,
            },
            dataset: {name, id, state, title, desc,}
        });

        rect.addEventListener('click', this.options.mouseClickPixelCallback);
        rect.addEventListener('dblclick', this.options.mouseDblClickPixelCallback);
        rect.addEventListener('mouseover', this.options.mouseOverPixelCallback);
        rect.addEventListener('mouseout', this.options.mouseOutPixelCallback);
        return rect;
    }

    _drawRow(row, y) {
        const g = this._createSVGElement('g', {class: 'gline'});
        g.dataset.id = row.id;
        __.ach(this.mContainer, g);
        const pixelsInLine = this.data.columns || row.series; // columns are optional
        for (let index in pixelsInLine) {
            const rect = this._createPixel(row.series[index] || false, index, y);
            __.ach(g, rect);
        }
    }

    _isShowXAxisName() {
        return this.options.xAxisName;
    }

    _isShowYAxisName() {
        return this.options.yAxisName;
    }

    _drawLabels() {
        this._drawXAxisName();
        this._drawXAxisLabels();
        this._drawYAxisName();
    }

    _drawYAxisName() {
        if (!this._isShowYAxisName()) {
            return;
        }
        const svgBox = this._getSvgBox();
        const label = this._createSVGElement('g', {class: 'matrix-labels yaxis'});
        const text = this._createSVGElement('text', {
            'text-anchor': 'middle',
            transform: `translate(15,${svgBox.height / 2})rotate(270)`
        });
        text.addEventListener('click', this.options.mouseYAxisClickCallback);
        text.innerHTML = this.options.yAxisName;
        __.ach(label, text);
        __.ach(this.svg, label);
    }

    _drawXAxisName() {
        if (!this._isShowXAxisName()) {
            return;
        }
        const svgBox = this._getSvgBox();
        const label = this._createSVGElement('g', {class: 'matrix-labels xaxis'});
        const text = this._createSVGElement('text', {
            'text-anchor': 'middle',
            x: svgBox.width / 2,
            y: svgBox.height - 5
        });
        text.addEventListener('click', this.options.mouseXAxisClickCallback);
        text.innerHTML = this.options.xAxisName;
        __.ach(label, text);
        __.ach(this.svg, label);
    }

    _drawXAxisLabels() {
        if (!this._isShowXAxisName()) {
            return;
        }
        const mContainerBox = this.mContainer.getBoundingClientRect();
        const labelBox = this.svg.querySelector('.xaxis');

        const mXZero = mContainerBox.x - this._getSvgBox().x;
        const mYMax = mContainerBox.height + this.settings.yShift;
        let shape = `M${mXZero - 5},${mYMax} l${mContainerBox.width + 10},0`;

        const hLine = this._createSVGElement('path', {
            'stroke-width': '1px',
            d: shape,
        });
        __.ach(labelBox, hLine);

        for (let i = 0; i < this._getMaxLengthSeries(); i++) {
            let label = this.options.xAxisLabelNameGetter(i);
            if (i === 0 && !label) {
                label = this.options.xAxisLabelNameGetter('first');
            }
            if (i === this._getMaxLengthSeries() - 1 && !label) {
                label = this.options.xAxisLabelNameGetter('last');
            }
            if (!label) continue;
            const x = mXZero + i * this.options.squareSize + this.options.squareSize / 2;
            shape = `M${x},${mYMax} l0,5`;
            const verticalLine = this._createSVGElement('path', {
                'stroke-width': '1px',
                d: shape
            });
            const textElement = this._createSVGElement('text', {
                'text-anchor': 'middle',
                x: x,
                y: mContainerBox.height + 20
            });
            textElement.innerHTML = label;
            __.ach(labelBox, verticalLine);
            __.ach(labelBox, textElement);
        }
    }

    _getMaxLengthSeries() {
        let max = 0;
        for (let i in this.data.rows) {
            max = this.data.rows[i].series.length > max ? this.data.rows[i].series.length : max;
        }
        return max;
    }

    _drawRows() {
        let y = 0;
        for (let i in this.data.rows) {
            this._drawRow(this.data.rows[i], y);
            y++;
        }
    }

    _getXShift() {
        return this._isShowYAxisName() ? this.settings.xShift + 20 : this.settings.xShift;
    }

    _prepareCanvas() {
        const data = this.data;
        __.clr(this.svg);
        let width = data.hasOwnProperty('columns') ? data.columns.length : this._getMaxLengthSeries();
        width = (width + 1) * this.options.squareSize;
        if (this._isShowYAxisName()) {
            width += this._getXShift();
        }
        let height = (data.rows.length + 1) * this.options.squareSize;
        if (this._isShowXAxisName()) {
            height += 20 + this.settings.yShift;
        }
        __.props(this.svg, {style: {height: `${height}px`, width: `${width}px`}});
        let background = this._createSVGElement('rect', {
            width: '100%',
            height: '100%',
            fill: this.options.backgroundColor
        });
        this.mContainer = this._createSVGElement('g', {class: 'mContainer'});
        __.ach(this.svg, background);
        __.ach(this.svg, this.mContainer);
    }
}
<commit_msg>Update matrix-chart.js<commit_after>class MatrixChart {
    constructor(parentElement, svgId, options = {}) {
        this.data = {};
        this.options = {
            backgroundColor: 'white',
            statusColorMap: { // background color
                0: 'green',
                1: 'red',
            },
            statusClassMap: { // css class
            },
            defaultStatus: 0,
            transpose: false,
            strokeWidth: 1,
            squareSize: 7,
            xAxis: {
                align: 'left',
                title: false,
                labelNameGetter: (columnIndex, min, max) => {
                    return false;
                },
                clickCallback: this._empty,
            },
            yAxis: {
                title: false,
                labelNameGetter: (columnIndex, min, max) => {
                    return false;
                },
                clickCallback: this._empty,
            },
            mouseOverCallback: this._empty,
            mouseOutCallback: this._empty,
            mouseClickPixelCallback: this._empty,
            mouseDblClickPixelCallback: this._empty,
            mouseOverPixelCallback: this._empty,
            mouseOutPixelCallback: this._empty,
        };
        this.settings = {
            axisStrokeLength: 8,
            xShift: 1.5 * this.options.squareSize,
            yShift: 1.5 * this.options.squareSize,
        };

        this.parentElement = __.cel('span', {}, parentElement);
        this.options = __.merge(this.options, options);
        this.shadow = this.parentElement.attachShadow({mode: 'open'});
        this.svg = this._createSVGRootElement(svgId);
        __.ach(this.shadow, this.svg);
    }

    _empty() {
    }

    /**
     *
     * data format:
     * ```
     * {
     * rows: [
     *          0: {
     *              id: ..,
     *              name: ...,
     *              series: [ // if not empty populate with non-default pixel statuses
     *                  53: 4,
     *                  99: 1,
     *                  103: {state: 2, text: '....'},
     *              ]
     *          }
     *      ],
     *      // columns IS OPTIONAL
     * columns: [
     *     ....
     *     53: {
     *          id: ...,
     *          name: ...
     *     }
     *  ],
     * customData: { // optional custom data
     *
     *  }
     * }
     *```
     * @param data
     */
    draw(data) {
        this.data = data;
        this._prepareCanvas();
        this._attachGlobalListeners();
        this._drawRows();
        this._drawLabels();
    }

    setOptions(options) {
        this.options = options;
    }

    getOptions() {
        return this.options;
    }

    getCustomData() {
        return this.data.customData || {};
    }

    getSvg() {
        return this.svg;
    }

    _attachGlobalListeners() {
        this.svg.addEventListener('mouseover', this.options.mouseOverCallback);
        this.svg.addEventListener('mouseout', this.options.mouseOutCallback);
    }

    _getSvgBox() {
        return this.svg.getBoundingClientRect();
    }

    _createSVGRootElement(id) {
        const root = this._createSVGElement('svg', {id: `svg-${id}`});
        if (this.options.hasOwnProperty('externalCss')) {
            __.cel('link', {
                rel: 'stylesheet',
                href: this.options.externalCss
            }, this.shadow);
        }
        return root;
    }

    _createSVGElement(tag, attrs = {}, title = false) {
        let el = document.createElementNS('http://www.w3.org/2000/svg', tag);
        __.attrs(el, attrs);
        if (!title) return el;
        el.innerHTML = `<title>${title}</title>`;
        return el;
    }

    _createPixel(pixelInfo, pixelX, pixelY) {
        const zoom = this.options.squareSize;
        let state = pixelInfo.hasOwnProperty('state') ? pixelInfo.state : pixelInfo;
        state = state === "undefined" ? this.options.defaultStatus : state;

        let x = this._getXShift() + pixelX * zoom - 0.5 * zoom;
        if (this.options.xAxis.align === 'right') {
            x = this._getSvgBox().width - pixelX * zoom - 2.5 * zoom;
        }
        let rect = this._createSVGElement('rect', {
            width: zoom,
            height: zoom,
            x,
            y: pixelY * zoom + this.settings.yShift,
        });
        const cssClass = this.options.statusClassMap[state] || false;
        if (cssClass) {
            rect.classList.add(cssClass);
        } else {
            rect.style.fill = this.options.statusColorMap[state] || this.options.statusColorMap[this.options.defaultStatus];
        }
        const name = this.data.hasOwnProperty('columns') ? this.data.columns[pixelX]['name'] : "undefined",
            id = this.data.hasOwnProperty('columns') ? this.data.columns[pixelX]['id'] : "undefined",
            title = pixelInfo.hasOwnProperty('title') ? encodeURIComponent(pixelInfo['title']) : "undefined",
            desc = pixelInfo['text'] || "undefined";
        __.props(rect, {
            style: {
                strokeWidth: `${this.options.strokeWidth}px`,
            },
            dataset: {name, id, state, title, desc,}
        });

        rect.addEventListener('click', this.options.mouseClickPixelCallback);
        rect.addEventListener('dblclick', this.options.mouseDblClickPixelCallback);
        rect.addEventListener('mouseover', this.options.mouseOverPixelCallback);
        rect.addEventListener('mouseout', this.options.mouseOutPixelCallback);
        return rect;
    }

    _drawRow(row, y) {
        const g = this._createSVGElement('g', {class: 'gline'});
        g.dataset.id = row.id;
        __.ach(this.mContainer, g);
        const pixelsInLine = this.data.columns || row.series; // columns are optional
        for (let index in pixelsInLine) {
            const rect = this._createPixel(row.series[index] || false, index, y);
            __.ach(g, rect);
        }
    }

    _isShowXAxisTitle() {
        return this.options.xAxis.title;
    }

    _isShowYAxisTitle() {
        return this.options.yAxis.title;
    }

    _drawLabels() {
        this._drawXAxisTitle();
        this._drawXAxisLabels();
        this._drawYAxisTitle();
        this._drawYAxisLabels();
    }

    _drawYAxisTitle() {
        if (!this._isShowYAxisTitle()) {
            return;
        }
        const svgBox = this._getSvgBox();
        const label = this._createSVGElement('g', {class: 'matrix-labels yaxis'});
        const text = this._createSVGElement('text', {
            'text-anchor': 'middle',
            transform: `translate(15,${svgBox.height / 2})rotate(270)`
        });
        text.addEventListener('click', this.options.yAxis.clickCallback);
        text.innerHTML = this.options.yAxis.title;
        __.ach(label, text);
        __.ach(this.svg, label);
    }

    _drawXAxisTitle() {
        if (!this._isShowXAxisTitle()) {
            return;
        }
        const svgBox = this._getSvgBox();
        const label = this._createSVGElement('g', {class: 'matrix-labels xaxis'});
        const text = this._createSVGElement('text', {
            'text-anchor': 'middle',
            x: svgBox.width / 2,
            y: svgBox.height - 5
        });
        text.addEventListener('click', this.options.xAxis.clickCallback);
        text.innerHTML = this.options.xAxis.title;
        __.ach(label, text);
        __.ach(this.svg, label);
    }

    _drawYAxisLabels() {
        if (!this._isShowYAxisTitle()) {
            return;
        }
        const mContainerBox = this.mContainer.getBoundingClientRect();
        const labelBox = this.svg.querySelector('.yaxis');

        const mXZero = mContainerBox.x - this._getSvgBox().x;
        const mYMin = this.settings.yShift - 5;
        let shape = `M${mXZero},${mYMin} l0,${mContainerBox.height + 10}`;

        let axis = this._createSVGElement('path', {
            'stroke-width': '1px',
            d: shape,
        });
        __.ach(labelBox, axis);
        /*
                for (let i = 0; i < this._getMaxLengthSeries(); i++) {
                    let label = this.options.xAxis.labelNameGetter(i);
                    if (i === 0 && !label) {
                        label = this.options.xAxis.labelNameGetter('first');
                    }
                    if (i === this._getMaxLengthSeries() - 1 && !label) {
                        label = this.options.xAxis.labelNameGetter('last');
                    }
                    if (!label) continue;
                    const x = mXZero + i * this.options.squareSize + this.options.squareSize / 2;
                    shape = `M${x},${mYMax} l0,5`;
                    const verticalLine = this._createSVGElement('path', {
                        'stroke-width': '1px',
                        d: shape
                    });
                    const textElement = this._createSVGElement('text', {
                        'text-anchor': 'middle',
                        x: x,
                        y: mContainerBox.height + 20
                    });
                    textElement.innerHTML = label;
                    __.ach(labelBox, verticalLine);
                    __.ach(labelBox, textElement);
                }
         */
    }

    _drawXAxisLabels() {
        if (!this._isShowXAxisTitle()) {
            return;
        }
        const mContainerBox = this.mContainer.getBoundingClientRect();
        const mainAaxisElement = this.svg.querySelector('.xaxis');
        const linesBox = this._createSVGElement('g');
        const labelsBox = this._createSVGElement('g');
        __.ach(mainAaxisElement, linesBox);
        __.ach(mainAaxisElement, labelsBox);

        const mXZero = mContainerBox.x - this._getSvgBox().x;
        const mYMax = mContainerBox.height + this.settings.yShift;
        let shape = `M${mXZero - 5},${mYMax} l${mContainerBox.width + 10},0`;

        let axis = this._createSVGElement('path', {
            'stroke-width': '1px',
            d: shape,
        });
        __.ach(linesBox, axis);

        let maxLength = this._getMaxLengthSeries();
        for (let i = 0; i < maxLength; i++) {
            const label = this.options.xAxis.labelNameGetter(i, 0, maxLength);
            if (!label) continue;
            const x = mXZero + i * this.options.squareSize + this.options.squareSize / 2;
            shape = `M${x},${mYMax} l0,${this.settings.axisStrokeLength}`;
            const stroke = this._createSVGElement('path', {
                'stroke-width': '1px',
                d: shape
            });
            __.ach(linesBox, stroke);

            const textElement = this._createSVGElement('text', {});
            textElement.innerHTML = label;
            __.ach(labelsBox, textElement);
            __.attrs(textElement, {
                'text-anchor': 'middle',
                x,
                y: mContainerBox.height + stroke.getBoundingClientRect().height + textElement.getBoundingClientRect().height + 3
            })
        }
    }

    _getMaxLengthSeries() {
        let max = 0;
        for (let i in this.data.rows) {
            max = this.data.rows[i].series.length > max ? this.data.rows[i].series.length : max;
        }
        return max;
    }

    _drawRows() {
        let y = 0;
        for (let i in this.data.rows) {
            this._drawRow(this.data.rows[i], y);
            y++;
        }
    }

    _getXShift() {
        return this._isShowYAxisTitle() ? this.settings.xShift + 25 : this.settings.xShift;
    }

    _prepareCanvas() {
        const data = this.data;
        __.clr(this.svg);
        let width = data.hasOwnProperty('columns') ? data.columns.length : this._getMaxLengthSeries();
        width = (width + 1) * this.options.squareSize;
        if (this._isShowXAxisTitle()) {
            width += this._getXShift();
        }
        let height = (data.rows.length + 1) * this.options.squareSize;
        if (this._isShowYAxisTitle()) {
            height += 35 + this.settings.yShift;
        }
        __.props(this.svg, {style: {height: `${height}px`, width: `${width}px`}});
        let background = this._createSVGElement('rect', {
            width: '100%',
            height: '100%',
            fill: this.options.backgroundColor
        });
        this.mContainer = this._createSVGElement('g', {class: 'mContainer'});
        __.ach(this.svg, background);
        __.ach(this.svg, this.mContainer);
    }
}
<|endoftext|>