<commit_before>// PORTAL DETAILS DISPLAY ////////////////////////////////////////////
// hand any of these functions the details-hash of a portal, and they
// will return pretty, displayable HTML or parts thereof.

// returns displayable text+link about portal range
window.getRangeText = function(d) {
  var range = getPortalRange(d);

  var title = 'Base range:\t' + digits(Math.floor(range.base))+'m'
    + '\nLink amp boost:\t×'+range.boost
    + '\nRange:\t'+digits(Math.floor(range.range))+'m';

  if(!range.isLinkable) title += '\nPortal is missing resonators,\nno new links can be made';

  return ['range',
      ''
    + (range.range > 1000
      ? Math.floor(range.range/1000) + ' km'
      : Math.floor(range.range)      + ' m')
    + ''];
}

// generates description text from details for portal
window.getPortalDescriptionFromDetails = function(details) {
  return details.title || '(untitled)';

//  var descObj = details.descriptiveText.map;
//  // FIXME: also get real description?
//  var desc = descObj.TITLE;
//  if(descObj.ADDRESS)
//    desc += '\n' + descObj.ADDRESS;
////  if(descObj.ATTRIBUTION)
////    desc += '\nby '+descObj.ATTRIBUTION+' ('+descObj.ATTRIBUTION_LINK+')';
//  return desc;
}

// Grabs more info, including the submitter name for the current main
// portal image
window.getPortalDescriptionFromDetailsExtended = function(details) {
  var descObj = details.title;
  var photoStreamObj = details.photoStreamInfo;

  var submitterObj = new Object();
  submitterObj.type = "";
  submitterObj.name = "";
  submitterObj.team = "";
  submitterObj.link = "";
  submitterObj.voteCount = undefined;

  if(photoStreamObj && photoStreamObj.hasOwnProperty("coverPhoto") && photoStreamObj.coverPhoto.hasOwnProperty("attributionMarkup")) {
    submitterObj.name = "Unknown";

    var attribution = photoStreamObj.coverPhoto.attributionMarkup;
    submitterObj.type = attribution[0];
    if(attribution[1].hasOwnProperty("plain"))
      submitterObj.name = attribution[1].plain;
    if(attribution[1].hasOwnProperty("team"))
      submitterObj.team = attribution[1].team;
    if(attribution[1].hasOwnProperty("attributionLink"))
      submitterObj.link = attribution[1].attributionLink;
    if(photoStreamObj.coverPhoto.hasOwnProperty("voteCount"))
      submitterObj.voteCount = photoStreamObj.coverPhoto.voteCount;
  }

  var portalDetails = {
    title: descObj.TITLE,
    description: descObj.DESCRIPTION,
    address: descObj.ADDRESS,
    submitter: submitterObj
  };

  return portalDetails;
}

// given portal details, returns html code to display mod details.
window.getModDetails = function(d) {
  var mods = [];
  var modsTitle = [];
  var modsColor = [];
  $.each(d.mods, function(ind, mod) {
    var modName = '';
    var modTooltip = '';
    var modColor = '#000';

    if (mod) {
      // all mods seem to follow the same pattern for the data structure
      // but let's try and make this robust enough to handle possible future differences

      modName = mod.name || '(unknown mod)';

      if (mod.rarity) {
        modName = mod.rarity.capitalize().replace(/_/g,' ') + ' ' + modName;
      }

      modTooltip = modName + '\n';
      if (mod.owner) {
        modTooltip += 'Installed by: '+ mod.owner + '\n';
      }

      if (mod.stats) {
        modTooltip += 'Stats:';
        for (var key in mod.stats) {
          if (!mod.stats.hasOwnProperty(key)) continue;
          var val = mod.stats[key];

//          if (key === 'REMOVAL_STICKINESS' && val == 0) continue;  // stat on all mods recently - unknown meaning, not displayed in stock client

          // special formatting for known mod stats, where the display of the raw value is less useful
          if (key === 'HACK_SPEED') val = (val/10000)+'%'; // 500000 = 50%
          else if (key === 'FORCE_AMPLIFIER') val = (val/1000)+'x';  // 2000 = 2x
          else if (key === 'LINK_RANGE_MULTIPLIER') val = (val/1000)+'x' // 2000 = 2x
          else if (key === 'HIT_BONUS') val = (val/10000)+'%'; // 2000 = 0.2% (although this seems pretty small to be useful?)
          else if (key === 'ATTACK_FREQUENCY') val = (val/1000)+'x' // 2000 = 2x
          // else display unmodified. correct for shield mitigation and multihack - unknown for future/other mods

          modTooltip += '\n+' +  val + ' ' + key.capitalize().replace(/_/g,' ');
        }
      }

      if (mod.rarity) {
        modColor = COLORS_MOD[mod.rarity];
      } else {
        modColor = '#fff';
      }
    }

    mods.push(modName);
    modsTitle.push(modTooltip);
    modsColor.push(modColor);
  });

  var t = '';
  for (var i=0; i<mods.length; i++) {
    t += ''+mods[i]+''
  }
  // and add blank entries if we have less than 4 mods (as the server no longer returns all mod slots, but just the filled ones)
  for (var i=mods.length; i<4; i++) {
    t += ''
  }

  return t;
}

window.getEnergyText = function(d) {
  var currentNrg = getCurrentPortalEnergy(d);
  var totalNrg = getTotalPortalEnergy(d);
  var inf = currentNrg + ' / ' + totalNrg;
  var fill = prettyEnergy(currentNrg) + ' / ' + prettyEnergy(totalNrg)
  return ['energy', '<tt title="'+inf+'">' + fill + '</tt>'];
}

window.getResonatorDetails = function(d) {
  var resoDetails = [];
  // octant=slot: 0=E, 1=NE, 2=N, 3=NW, 4=W, 5=SW, 6=S, SE=7
  // resos in the display should be ordered like this:
  //   N    NE         Since the view is displayed in rows, they
  //  NW    E          need to be ordered like this: N NE NW E W SE SW S
  //   W    SE         i.e. 2 1 3 0 4 7 5 6
  //  SW    S
  // note: as of 2014-05-23 update, this is not true for portals with empty slots!

  var processResonatorSlot = function(reso,slot) {
    var lvl=0, nrg=0, owner=null;

    if (reso) {
      lvl = parseInt(reso.level);
      nrg = parseInt(reso.energy);
      owner = reso.owner;
    }

    resoDetails.push(renderResonatorDetails(slot, lvl, nrg, owner));
  };

  // if all 8 resonators are deployed, we know which is in which slot

  if (d.resonators.length == 8) {
    // fully deployed - we can make assumptions about deployment slots
    $.each([2, 1, 3, 0, 4, 7, 5, 6], function(ind, slot) {
      processResonatorSlot(d.resonators[slot],slot);
    });
  } else {
    // partially deployed portal - we can no longer find out which resonator is in which slot
    for(var ind=0; ind<8; ind++) {
      processResonatorSlot(ind < d.resonators.length ? d.resonators[ind] : null, null);
    }

  }

  return '
' + genFourColumnTable(resoDetails) + '
';

}

// helper function that renders the HTML for a given resonator. Does
// not work with raw details-hash. Needs digested infos instead:
// slot: which slot this resonator occupies. Starts with 0 (east) and
// rotates clockwise. So, last one is 7 (southeast).
window.renderResonatorDetails = function(slot, level, nrg, nick) {
  if(OCTANTS[slot] === 'N')
    var className = 'meter north';
  else
    var className = 'meter';

  var max = RESO_NRG[level];
  var fillGrade = level > 0 ? nrg/max*100 : 0;

  var inf = (level > 0 ? 'energy:\t' + nrg   + ' / ' + max + ' (' + Math.round(fillGrade) + '%)\n'
                        +'level:\t'  + level + '\n'
                        +'owner:\t'  + nick  + '\n'
                       : '')
          + (slot !== null ? 'octant:\t' + OCTANTS[slot] + ' ' + OCTANTS_ARROW[slot]:'');

  var style = fillGrade ? 'width:'+fillGrade+'%; background:'+COLORS_LVL[level]+';':'';

  var color = (level < 3 ? "#9900FF" : "#FFFFFF");

  var lbar = level > 0 ? ' L ' + level + ' ' : '';

  var fill  = '';

  var meter = '' + fill + lbar + '';

  nick = nick ? ''+nick+'' : null;
  return [meter, nick || ''];
}

// calculate AP gain from destroying portal and then capturing it by deploying resonators
window.getAttackApGainText = function(d,fieldCount,linkCount) {
  var breakdown = getAttackApGain(d,fieldCount,linkCount);
  var totalGain = breakdown.enemyAp;

  function tt(text) {
    var t = '';
    if (teamStringToId(PLAYER.team) == teamStringToId(d.team)) {
      totalGain = breakdown.friendlyAp;
      t += 'Friendly AP:\t' + breakdown.friendlyAp + '\n';
      t += '  Deploy ' + breakdown.deployCount + ', ';
      t += 'Upgrade ' + breakdown.upgradeCount + '\n';
      t += '\n';
    }
    t += 'Enemy AP:\t' + breakdown.enemyAp + '\n';
    t += '  Destroy AP:\t' + breakdown.destroyAp + '\n';
    t += '  Capture AP:\t' + breakdown.captureAp + '\n';
    return '<tt title="' + t + '">' + text + '</tt>';
  }

  return [tt('AP Gain'), tt(digits(totalGain))];
}

window.getHackDetailsText = function(d) {
  var hackDetails = getPortalHackDetails(d);

  var shortHackInfo = hackDetails.hacks+' @ '+formatInterval(hackDetails.cooldown);

  function tt(text) {
    var t = 'Hacks available every 4 hours\n';
    t += 'Hack count:\t'+hackDetails.hacks+'\n';
    t += 'Cooldown time:\t'+formatInterval(hackDetails.cooldown)+'\n';
    t += 'Burnout time:\t'+formatInterval(hackDetails.burnout)+'\n';

    return ''+text+'';
  }

  return [tt('hacks'), tt(shortHackInfo)];
}

window.getMitigationText = function(d,linkCount) {
  var mitigationDetails = getPortalMitigationDetails(d,linkCount);

  var mitigationShort = mitigationDetails.total;
  if (mitigationDetails.excess) mitigationShort += ' (+'+mitigationDetails.excess+')';

  function tt(text) {
    var t = 'Total shielding:\t'+(mitigationDetails.shields+mitigationDetails.links)+'\n'
          + '- active:\t'+mitigationDetails.total+'\n'
          + '- excess:\t'+mitigationDetails.excess+'\n'
          + 'From\n'
          + '- shields:\t'+mitigationDetails.shields+'\n'
          + '- links:\t'+mitigationDetails.links;

    return ''+text+'';
  }

  return [tt('shielding'), tt(mitigationShort)];
}
<commit_msg>Update portal_detail_display_tools.js<commit_after>// PORTAL DETAILS DISPLAY ////////////////////////////////////////////
// hand any of these functions the details-hash of a portal, and they
// will return pretty, displayable HTML or parts thereof.

// returns displayable text+link about portal range
window.getRangeText = function(d) {
  var range = getPortalRange(d);

  var title = 'Base range:\t' + digits(Math.floor(range.base))+'m'
    + '\nLink amp boost:\t×'+range.boost
    + '\nRange:\t'+digits(Math.floor(range.range))+'m';

  if(!range.isLinkable) title += '\nPortal is missing resonators,\nno new links can be made';

  return ['range',
      ''
    + (range.range > 1000
      ? Math.floor(range.range/1000) + ' km'
      : Math.floor(range.range)      + ' m')
    + ''];
}

// generates description text from details for portal
window.getPortalDescriptionFromDetails = function(details) {
  return details.title || '(untitled)';

//  var descObj = details.descriptiveText.map;
//  // FIXME: also get real description?
//  var desc = descObj.TITLE;
//  if(descObj.ADDRESS)
//    desc += '\n' + descObj.ADDRESS;
////  if(descObj.ATTRIBUTION)
////    desc += '\nby '+descObj.ATTRIBUTION+' ('+descObj.ATTRIBUTION_LINK+')';
//  return desc;
}

// Grabs more info, including the submitter name for the current main
// portal image
window.getPortalDescriptionFromDetailsExtended = function(details) {
  var descObj = details.title;
  var photoStreamObj = details.photoStreamInfo;

  var submitterObj = new Object();
  submitterObj.type = "";
  submitterObj.name = "";
  submitterObj.team = "";
  submitterObj.link = "";
  submitterObj.voteCount = undefined;

  if(photoStreamObj && photoStreamObj.hasOwnProperty("coverPhoto") && photoStreamObj.coverPhoto.hasOwnProperty("attributionMarkup")) {
    submitterObj.name = "Unknown";

    var attribution = photoStreamObj.coverPhoto.attributionMarkup;
    submitterObj.type = attribution[0];
    if(attribution[1].hasOwnProperty("plain"))
      submitterObj.name = attribution[1].plain;
    if(attribution[1].hasOwnProperty("team"))
      submitterObj.team = attribution[1].team;
    if(attribution[1].hasOwnProperty("attributionLink"))
      submitterObj.link = attribution[1].attributionLink;
    if(photoStreamObj.coverPhoto.hasOwnProperty("voteCount"))
      submitterObj.voteCount = photoStreamObj.coverPhoto.voteCount;
  }

  var portalDetails = {
    title: descObj.TITLE,
    description: descObj.DESCRIPTION,
    address: descObj.ADDRESS,
    submitter: submitterObj
  };

  return portalDetails;
}

// given portal details, returns html code to display mod details.
window.getModDetails = function(d) {
  var mods = [];
  var modsTitle = [];
  var modsColor = [];
  $.each(d.mods, function(ind, mod) {
    var modName = '';
    var modTooltip = '';
    var modColor = '#000';

    if (mod) {
      // all mods seem to follow the same pattern for the data structure
      // but let's try and make this robust enough to handle possible future differences

      modName = mod.name || '(unknown mod)';

      if (mod.rarity) {
        modName = mod.rarity.capitalize().replace(/_/g,' ') + ' ' + modName;
      }

      modTooltip = modName + '\n';
      if (mod.owner) {
        modTooltip += 'Installed by: '+ mod.owner + '\n';
      }

      if (mod.stats) {
        modTooltip += 'Stats:';
        for (var key in mod.stats) {
          if (!mod.stats.hasOwnProperty(key)) continue;
          var val = mod.stats[key];

//          if (key === 'REMOVAL_STICKINESS' && val == 0) continue;  // stat on all mods recently - unknown meaning, not displayed in stock client

          // special formatting for known mod stats, where the display of the raw value is less useful
          if (key === 'HACK_SPEED') val = (val/10000)+'%'; // 500000 = 50%
          else if (key === 'FORCE_AMPLIFIER') val = (val/1000)+'x';  // 2000 = 2x
          else if (key === 'LINK_RANGE_MULTIPLIER') val = (val/1000)+'x' // 2000 = 2x
          else if (key === 'HIT_BONUS') val = (val/10000)+'%'; // 2000 = 0.2% (although this seems pretty small to be useful?)
          else if (key === 'ATTACK_FREQUENCY') val = (val/1000)+'x' // 2000 = 2x
          // else display unmodified. correct for shield mitigation and multihack - unknown for future/other mods

          modTooltip += '\n+' +  val + ' ' + key.capitalize().replace(/_/g,' ');
        }
      }

      if (mod.rarity) {
        modColor = COLORS_MOD[mod.rarity];
      } else {
        modColor = '#fff';
      }
    }

    mods.push(modName);
    modsTitle.push(modTooltip);
    modsColor.push(modColor);
  });

  var t = '';
  for (var i=0; i<mods.length; i++) {
    t += ''+mods[i]+''
  }
  // and add blank entries if we have less than 4 mods (as the server no longer returns all mod slots, but just the filled ones)
  for (var i=mods.length; i<4; i++) {
    t += ''
  }

  return t;
}

window.getEnergyText = function(d) {
  var currentNrg = getCurrentPortalEnergy(d);
  var totalNrg = getTotalPortalEnergy(d);
  var inf = currentNrg + ' / ' + totalNrg;
  var fill = prettyEnergy(currentNrg) + ' / ' + prettyEnergy(totalNrg)
  return ['energy', '<tt title="'+inf+'">' + fill + '</tt>'];
}

window.getResonatorDetails = function(d) {
  var resoDetails = [];
  // octant=slot: 0=E, 1=NE, 2=N, 3=NW, 4=W, 5=SW, 6=S, SE=7
  // resos in the display should be ordered like this:
  //   N    NE         Since the view is displayed in rows, they
  //  NW    E          need to be ordered like this: N NE NW E W SE SW S
  //   W    SE         i.e. 2 1 3 0 4 7 5 6
  //  SW    S
  // note: as of 2014-05-23 update, this is not true for portals with empty slots!

  var processResonatorSlot = function(reso,slot) {
    var lvl=0, nrg=0, owner=null;

    if (reso) {
      lvl = parseInt(reso.level);
      nrg = parseInt(reso.energy);
      owner = reso.owner;
    }

    resoDetails.push(renderResonatorDetails(slot, lvl, nrg, owner));
  };

  // if all 8 resonators are deployed, we know which is in which slot

  if (d.resonators.length == 8) {
    // fully deployed - we can make assumptions about deployment slots
    $.each([2, 1, 3, 0, 4, 7, 5, 6], function(ind, slot) {
      processResonatorSlot(d.resonators[slot],slot);
    });
  } else {
    // partially deployed portal - we can no longer find out which resonator is in which slot
    for(var ind=0; ind<8; ind++) {
      processResonatorSlot(ind < d.resonators.length ? d.resonators[ind] : null, null);
    }

  }

  return '
' + genFourColumnTable(resoDetails) + '
';

}

// helper function that renders the HTML for a given resonator. Does
// not work with raw details-hash. Needs digested infos instead:
// slot: which slot this resonator occupies. Starts with 0 (east) and
// rotates clockwise. So, last one is 7 (southeast).
window.renderResonatorDetails = function(slot, level, nrg, nick) {
  if(OCTANTS[slot] === 'N')
    var className = 'meter north';
  else
    var className = 'meter';

  var max = RESO_NRG[level];
  var fillGrade = level > 0 ? nrg/max*100 : 0;

  var inf = (level > 0 ? 'energy:\t' + nrg   + ' / ' + max + ' (' + Math.round(fillGrade) + '%)\n'
                        +'level:\t'  + level + '\n'
                        +'owner:\t'  + nick  + '\n'
                       : '')
          + (slot !== null ? 'octant:\t' + OCTANTS[slot] + ' ' + OCTANTS_ARROW[slot]:'');

  var style = fillGrade ? 'width:'+fillGrade+'%; background:'+COLORS_LVL[level]+';':'';

  var color = (level < 3 ? "#9900FF" : "#FFFFFF");

  var lbar = level > 0 ? ' L ' + level + ' ' : '';

  var fill  = '';

  var meter = '' + fill + lbar + '';

  nick = nick ? ''+nick+'' : null;
  return [meter, nick || ''];
}

// calculate AP gain from destroying portal and then capturing it by deploying resonators
window.getAttackApGainText = function(d,fieldCount,linkCount) {
  var breakdown = getAttackApGain(d,fieldCount,linkCount);
  var totalGain = breakdown.enemyAp;

  function tt(text) {
    var t = '';
    if (teamStringToId(PLAYER.team) == teamStringToId(d.team)) {
      totalGain = breakdown.friendlyAp;
      t += 'Friendly AP:\t' + breakdown.friendlyAp + '\n';
      t += '  Deploy ' + breakdown.deployCount + ', ';
      t += 'Upgrade ' + breakdown.upgradeCount + '\n';
      t += '\n';
    }
    t += 'Enemy AP:\t' + breakdown.enemyAp + '\n';
    t += '  Destroy AP:\t' + breakdown.destroyAp + '\n';
    t += '  Capture AP:\t' + breakdown.captureAp + '\n';
    return '<tt title="' + t + '">' + text + '</tt>';
  }

  return [tt('AP Gain'), tt(digits(totalGain))];
}

window.getHackDetailsText = function(d) {
  var hackDetails = getPortalHackDetails(d);

  var shortHackInfo = hackDetails.hacks+' @ '+formatInterval(hackDetails.cooldown);

  function tt(text) {
    var t = 'Hacks available every 4 hours\n';
    t += 'Hack count:\t'+hackDetails.hacks+'\n';
    t += 'Cooldown time:\t'+formatInterval(hackDetails.cooldown)+'\n';
    t += 'Burnout time:\t'+formatInterval(hackDetails.burnout)+'\n';

    return ''+text+'';
  }

  return [tt('hacks'), tt(shortHackInfo)];
}

window.getMitigationText = function(d,linkCount) {
  var mitigationDetails = getPortalMitigationDetails(d,linkCount);

  var mitigationShort = mitigationDetails.total;
  if (mitigationDetails.excess) mitigationShort += ' (+'+mitigationDetails.excess+')';

  function tt(text) {
    var t = 'Total shielding:\t'+(mitigationDetails.shields+mitigationDetails.links)+'\n'
          + '- active:\t'+mitigationDetails.total+'\n'
          + '- excess:\t'+mitigationDetails.excess+'\n'
          + 'From\n'
          + '- shields:\t'+mitigationDetails.shields+'\n'
          + '- links:\t'+mitigationDetails.links;

    return ''+text+'';
  }

  return [tt('shielding'), tt(mitigationShort)];
}
<|endoftext|>


<commit_before>"use strict";

const
    childProcess = require("child_process"),
    url = require("url"),
    BASE_URL = "/git/";

/*
 * status:
 * ?? <path> New file
 *  M <path> Modified
 * AM <path> Added / modified file
 *  D <path> Deleted
 *
 * Recover delete file (before commit):
 * checkout <path>
 *
 * Adding a new file
 * add <path>
 *
 * commit -m "message" <path>
 *
 */

module.exports = (request, response, next) => {

    if (0 !== request.url.indexOf(BASE_URL)) {
        return next();
    }

    const
        parameters = url.parse(request.url).pathname.substr(BASE_URL.length),
        process = childProcess.exec("git " + parameters + " --porcelain");

    response.setHeader("Content-Type", "text/plain; charset=utf-8");

    process.stdout.on("data", text => response.write(text));

    process.on("close", () => response.end());

};
<commit_msg>!yoda style (#280)<commit_after>"use strict";

const
    childProcess = require("child_process"),
    url = require("url"),
    BASE_URL = "/git/";

/*
 * status:
 * ?? <path> New file
 *  M <path> Modified
 * AM <path> Added / modified file
 *  D <path> Deleted
 *
 * Recover delete file (before commit):
 * checkout <path>
 *
 * Adding a new file
 * add <path>
 *
 * commit -m "message" <path>
 *
 */

module.exports = (request, response, next) => {

    if (request.url.indexOf(BASE_URL) !== 0) {
        return next();
    }

    const
        parameters = url.parse(request.url).pathname.substr(BASE_URL.length),
        process = childProcess.exec("git " + parameters + " --porcelain");

    response.setHeader("Content-Type", "text/plain; charset=utf-8");

    process.stdout.on("data", text => response.write(text));

    process.on("close", () => response.end());

};
<|endoftext|>


<commit_before>/*
 *  MainScene.js
 *  2014/06/19
 *  @auther minimo
 *  This Program is MIT license.
 *
 */

tm.define("tmapp.MainScene", {
    superClass: tm.app.Scene,

    //フラグ類
    numStage: 0,
    maxStage: 5,

    //遷移情報
    startGame: false,
    exitGame: false,
    retryStart: false,
    clearStage: false,
    stopTimer: false,

    //残弾数
    leftBullet: 15,

    //ヒット数
    numHit: 0,

    //タッチ情報
    startX: 0,
    startY: 0,
    touchTime: 0,
    moveX: 0,
    moveY: 0,
    beforeX: 0,
    beforeY: 0,

    //経過時間
    time: 1,

    //ゲーム内時計(ms)
    gameTime: 0,
    clearTime: [],

    //ラベル用パラメータ
    labelParamBasic: {fontFamily: "UbuntuMono", align: "left", baseline: "middle",outlineWidth: 3, fontWeight:700},
    labelParamCenter: {fontFamily: "UbuntuMono", align: "center", baseline: "middle",outlineWidth: 3, fontWeight:700},
    digitalCenterParam: {fontFamily: "Digital", align: "center", baseline: "middle",outlineWidth: 3, fontWeight:700},

    init: function(retry) {
        this.superInit();
        this.background = "rgba(0, 0, 0, 0.0)";

        //バックグラウンド
        this.bg = tm.display.RectangleShape({width: SC_W, height: SC_H, fillStyle: appMain.bgColor, strokeStyle: appMain.bgColor})
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.5)

        this.wall = tm.display.Sprite("wall", SC_W, SC_H)
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.5)

        //レイヤー準備
        this.lowerLayer = tm.app.Object2D().addChildTo(this);
        this.mainLayer = tm.app.Object2D().addChildTo(this);
        this.upperLayer = tm.app.Object2D().addChildTo(this);

        //床
        this.floor = [];
        for (var y = 0; y < 4; y++) {
            for (var x = 0; x < 10; x++) {
                tm.display.Sprite("block", 64, 64)
                    .addChildTo(this.lowerLayer)
                    .setPosition(x*64, SC_H*0.3+SC_H*y*0.15)
                    .setOrigin(0,0);
            }
            this.floor[y] = SC_H*0.3+SC_H*y*0.15-48;
        }

        //タイム表示
        var that = this;
        this.timeLabel = tm.display.OutlineLabel("00.00", 100)
            .addChildTo(this)
            .setParam({fontFamily: "Digital", align: "center", baseline: "middle",outlineWidth: 3, fontWeight:700})
            .setPosition(SC_W*0.5, SC_H*0.1);
        this.timeLabel.score = 0;
        this.timeLabel.update = function() {
            var time = (that.gameTime/10).floor();
            this.text = ""+(time/100);
            if (time%100 === 0 ) this.text += ".0";
            if (time%10 === 0 ) this.text += "0";
            if (time < 1000) this.text = "0"+this.text;
        }

        //残弾数表示
        this.bulletLabel = tm.display.OutlineLabel("15", 80)
            .addChildTo(this)
            .setParam({fontFamily: "Digital", align: "center", baseline: "middle",outlineWidth: 3, fontWeight:700})
            .setPosition(SC_W*0.5, SC_H*0.85);
        this.bulletLabel.update = function() {
            this.text = ""+that.leftBullet;
        }

        //ポーズボタン
        this.pause = tm.extension.Button(200, 60, "PAUSE", {flat: true, fontSize:40})
            .addChildTo(this)
            .setPosition(SC_W*0.84, 30)
            .addEventListener("pushed", function() {
                appMain.pushScene(tmapp.PauseScene(this));
            }.bind(this));

        //ステージ情報
        this.numStage = 1;

        //初期化
        this.startup();

        //目隠し
        this.mask = tm.display.RectangleShape({width: SC_W, height: SC_H, fillStyle: "rgba(0, 0, 0, 1.0)", strokeStyle: "rgba(0, 0, 0, 1.0)"})
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.5);
        this.mask.tweener.clear().fadeOut(200);
    },

    update: function(app) {
        if (!this.startGame) return;

        if (!this.stopTimer) {
            this.gameTime += app.deltaTime;
            if (this.gameTime < 0) this.gameTime = 0;
            if (this.gameTime > 100000) this.gameTime = 100000;
        }

        //ステージクリア条件チェック
        if (this.checkStageClear()) {
            if (!this.clearStage) {
                var that = this;
                this.stopTimer = true;
                this.clearTime[this.numStage] = this.gameTime;
                this.clearStage = true;

                var st = tm.display.Label("STAGE CLEAR", 80)
                    .addChildTo(this)
                    .setParam(this.digitalCenterParam)
                    .setPosition(SC_W*0.5, SC_H*0.5)
                    .setAlpha(0);
                st.tweener.clear()
                    .wait(3000)
                    .fadeIn(10)
                    .wait(2000)
                    .fadeOut(10)
                    .call(function() {
                        that.numStage++;
                        that.startup();
                        st.remove();
                    });
            }
        }

        //ゲームオーバー条件チェック
        if (this.leftBullet == 0 && !this.clearStage) {
            var that = this;
            var st = tm.display.Label("GAME OVER", 80)
                .addChildTo(this)
                .setParam(this.digitalCenterParam)
                .setPosition(SC_W*0.5, SC_H*0.5)
                .setAlpha(0);
            st.tweener.clear()
                .wait(2000)
                .fadeIn(10)
                .call(function() {
                    that.stopTimer = true;
                })
                .wait(2000)
                .fadeOut(10)
                .call(function() {
                    st.remove();
                    var param = {
                        maxStage: that.maxStage,
                        clearTime: that.clearTime,
                    };
                    appMain.pushScene(tmapp.GameoverScene());
                });
        }
    },

    //ゲーム開始表示
    startup: function() {
        var that = this;

        this.clearStage = false;
        this.numHit = 0;

        var st = tm.display.Label("STAGE "+this.numStage, 100)
            .addChildTo(this)
            .setParam(this.labelParamCenter)
            .setPosition(SC_W*0.5, SC_H*-1.0);
        st.tweener.clear()
            .move(SC_W*0.5, SC_H*0.5, 600, "easeOutSine")
            .wait(1000)
            .call(function() {
                st.fontSize = 200;
                st.text = "3";
            })
            .fadeOut(1000)
            .call(function() {
                st.text = "2";
            })
            .fadeIn(1).fadeOut(1000)
            .call(function() {
                st.text = "1";
            })
            .fadeIn(1).fadeOut(1000)
            .call(function() {
                that.startGame = true;
                that.stopTimer = false;
                that.setupStage();
                st.text = "START"
            })
            .fadeIn(1).wait(500).fadeOut(200)
            .call(function() {
                st.remove();
            });
    },

    //ステージ構築
    setupStage: function() {
    if (this.numStage == 1) {
        var x = SC_W*(rand(1,9)*0.1);
            var y = rand(0,4);
            tmapp.Target(1, 0)
                .addChildTo(this.mainLayer)
                .setPosition(x, this.floor[y]);
        }
        if (this.numStage == 2) {
            var x = SC_W*(rand(1,9)*0.1);
            var y = rand(0,4);
            tmapp.Target(1, 0)
                .addChildTo(this.mainLayer)
                .setPosition(x, this.floor[y]);

            var x = SC_W*(rand(1,9)*0.1);
            var y = rand(0,4);
            tmapp.Target(1, 1)
                .addChildTo(this.mainLayer)
                .setPosition(x, this.floor[y]);

            var x = SC_W*(rand(1,9)*0.1);
            var y = rand(0,4);
            tmapp.Target(1, 1)
                .addChildTo(this.mainLayer)
                .setPosition(x, this.floor[y]);
        }
    },

    //ステージクリア条件達成チェック
    checkStageClear: function() {
        if (this.numStage === 1) {
            if (this.numHit > 0) return true;
        }
        if (this.numStage === 2) {
            if (this.numHit > 2) return true;
        }
        return false;
    },

    //着弾エフェクト
    addImpact: function(x, y) {
        var p = tm.display.AnimationSprite(tmapp.SpriteSheet.Impact)
            .addChildTo(this)
            .setPosition(x, y)
            .setScale(2)
            .gotoAndPlay("impact");
        p.onanimationend = function() {
            this.remove();
        }
    },

    //ターゲット当り判定
    checkCollision: function(x, y) {
        var list = this.mainLayer.children;
        list.forEach(function(e, i, a) {
            if (e.isHitPoint(x, y)) {
                if (e.damage(x, y)) this.numHit++;
            }
        }.bind(this));
    },

    //ゲームオーバー
    gameover: function() {
    },

    ontouchstart: function(e) {
        if (this.startGame && !this.stopTimer) {
            if (this.leftBullet > 0) {
                this.leftBullet--;
                appMain.playSE("bang");
                this.addImpact(e.pointing.x, e.pointing.y);
                this.checkCollision(e.pointing.x, e.pointing.y);
            } else {
                appMain.playSE("bang");
            }
        }
    },

    ontouchmove: function(e) {
    },

    ontouchend: function(e) {
    },
});

<commit_msg>fix double hit<commit_after>/*
 *  MainScene.js
 *  2014/06/19
 *  @auther minimo
 *  This Program is MIT license.
 *
 */

tm.define("tmapp.MainScene", {
    superClass: tm.app.Scene,

    //フラグ類
    numStage: 0,
    maxStage: 5,

    //遷移情報
    startGame: false,
    exitGame: false,
    retryStart: false,
    clearStage: false,
    stopTimer: false,

    //残弾数
    leftBullet: 15,

    //ヒット数
    numHit: 0,

    //タッチ情報
    startX: 0,
    startY: 0,
    touchTime: 0,
    moveX: 0,
    moveY: 0,
    beforeX: 0,
    beforeY: 0,

    //経過時間
    time: 1,

    //ゲーム内時計(ms)
    gameTime: 0,
    clearTime: [],

    //ラベル用パラメータ
    labelParamBasic: {fontFamily: "UbuntuMono", align: "left", baseline: "middle",outlineWidth: 3, fontWeight:700},
    labelParamCenter: {fontFamily: "UbuntuMono", align: "center", baseline: "middle",outlineWidth: 3, fontWeight:700},
    digitalCenterParam: {fontFamily: "Digital", align: "center", baseline: "middle",outlineWidth: 3, fontWeight:700},

    init: function(retry) {
        this.superInit();
        this.background = "rgba(0, 0, 0, 0.0)";

        //バックグラウンド
        this.bg = tm.display.RectangleShape({width: SC_W, height: SC_H, fillStyle: appMain.bgColor, strokeStyle: appMain.bgColor})
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.5)

        this.wall = tm.display.Sprite("wall", SC_W, SC_H)
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.5)

        //レイヤー準備
        this.lowerLayer = tm.app.Object2D().addChildTo(this);
        this.mainLayer = tm.app.Object2D().addChildTo(this);
        this.upperLayer = tm.app.Object2D().addChildTo(this);

        //床
        this.floor = [];
        for (var y = 0; y < 4; y++) {
            for (var x = 0; x < 10; x++) {
                tm.display.Sprite("block", 64, 64)
                    .addChildTo(this.lowerLayer)
                    .setPosition(x*64, SC_H*0.3+SC_H*y*0.15)
                    .setOrigin(0,0);
            }
            this.floor[y] = SC_H*0.3+SC_H*y*0.15-48;
        }

        //タイム表示
        var that = this;
        this.timeLabel = tm.display.OutlineLabel("00.00", 100)
            .addChildTo(this)
            .setParam({fontFamily: "Digital", align: "center", baseline: "middle",outlineWidth: 3, fontWeight:700})
            .setPosition(SC_W*0.5, SC_H*0.1);
        this.timeLabel.score = 0;
        this.timeLabel.update = function() {
            var time = (that.gameTime/10).floor();
            this.text = ""+(time/100);
            if (time%100 === 0 ) this.text += ".0";
            if (time%10 === 0 ) this.text += "0";
            if (time < 1000) this.text = "0"+this.text;
        }

        //残弾数表示
        this.bulletLabel = tm.display.OutlineLabel("15", 80)
            .addChildTo(this)
            .setParam({fontFamily: "Digital", align: "center", baseline: "middle",outlineWidth: 3, fontWeight:700})
            .setPosition(SC_W*0.5, SC_H*0.85);
        this.bulletLabel.update = function() {
            this.text = ""+that.leftBullet;
        }

        //ポーズボタン
        this.pause = tm.extension.Button(200, 60, "PAUSE", {flat: true, fontSize:40})
            .addChildTo(this)
            .setPosition(SC_W*0.84, 30)
            .addEventListener("pushed", function() {
                appMain.pushScene(tmapp.PauseScene(this));
            }.bind(this));

        //ステージ情報
        this.numStage = 1;

        //初期化
        this.startup();

        //目隠し
        this.mask = tm.display.RectangleShape({width: SC_W, height: SC_H, fillStyle: "rgba(0, 0, 0, 1.0)", strokeStyle: "rgba(0, 0, 0, 1.0)"})
            .addChildTo(this)
            .setPosition(SC_W*0.5, SC_H*0.5);
        this.mask.tweener.clear().fadeOut(200);
    },

    update: function(app) {
        if (!this.startGame) return;

        if (!this.stopTimer) {
            this.gameTime += app.deltaTime;
            if (this.gameTime < 0) this.gameTime = 0;
            if (this.gameTime > 100000) this.gameTime = 100000;
        }

        //ステージクリア条件チェック
        if (this.checkStageClear()) {
            if (!this.clearStage) {
                var that = this;
                this.stopTimer = true;
                this.clearTime[this.numStage] = this.gameTime;
                this.clearStage = true;

                var st = tm.display.Label("STAGE CLEAR", 80)
                    .addChildTo(this)
                    .setParam(this.digitalCenterParam)
                    .setPosition(SC_W*0.5, SC_H*0.5)
                    .setAlpha(0);
                st.tweener.clear()
                    .wait(3000)
                    .fadeIn(10)
                    .wait(2000)
                    .fadeOut(10)
                    .call(function() {
                        that.numStage++;
                        that.startup();
                        st.remove();
                    });
            }
        }

        //ゲームオーバー条件チェック
        if (this.leftBullet == 0 && !this.clearStage) {
            var that = this;
            var st = tm.display.Label("GAME OVER", 80)
                .addChildTo(this)
                .setParam(this.digitalCenterParam)
                .setPosition(SC_W*0.5, SC_H*0.5)
                .setAlpha(0);
            st.tweener.clear()
                .wait(2000)
                .fadeIn(10)
                .call(function() {
                    that.stopTimer = true;
                })
                .wait(2000)
                .fadeOut(10)
                .call(function() {
                    st.remove();
                    var param = {
                        maxStage: that.maxStage,
                        clearTime: that.clearTime,
                    };
                    appMain.pushScene(tmapp.GameoverScene());
                });
        }
    },

    //ゲーム開始表示
    startup: function() {
        var that = this;

        this.clearStage = false;
        this.numHit = 0;

        var st = tm.display.Label("STAGE "+this.numStage, 100)
            .addChildTo(this)
            .setParam(this.labelParamCenter)
            .setPosition(SC_W*0.5, SC_H*-1.0);
        st.tweener.clear()
            .move(SC_W*0.5, SC_H*0.5, 600, "easeOutSine")
            .wait(1000)
            .call(function() {
                st.fontSize = 200;
                st.text = "3";
            })
            .fadeOut(1000)
            .call(function() {
                st.text = "2";
            })
            .fadeIn(1).fadeOut(1000)
            .call(function() {
                st.text = "1";
            })
            .fadeIn(1).fadeOut(1000)
            .call(function() {
                that.startGame = true;
                that.stopTimer = false;
                that.setupStage();
                st.text = "START"
            })
            .fadeIn(1).wait(500).fadeOut(200)
            .call(function() {
                st.remove();
            });
    },

    //ステージ構築
    setupStage: function() {
    if (this.numStage == 1) {
        var x = SC_W*(rand(1,9)*0.1);
            var y = rand(0,4);
            tmapp.Target(1, 0)
                .addChildTo(this.mainLayer)
                .setPosition(x, this.floor[y]);
        }
        if (this.numStage == 2) {
            var x = SC_W*(rand(1,9)*0.1);
            var y = rand(0,4);
            tmapp.Target(1, 0)
                .addChildTo(this.mainLayer)
                .setPosition(x, this.floor[y]);

            var x = SC_W*(rand(1,9)*0.1);
            var y = rand(0,4);
            tmapp.Target(1, 1)
                .addChildTo(this.mainLayer)
                .setPosition(x, this.floor[y]);

            var x = SC_W*(rand(1,9)*0.1);
            var y = rand(0,4);
            tmapp.Target(1, 1)
                .addChildTo(this.mainLayer)
                .setPosition(x, this.floor[y]);
        }
    },

    //ステージクリア条件達成チェック
    checkStageClear: function() {
        if (this.numStage === 1) {
            if (this.numHit > 0) return true;
        }
        if (this.numStage === 2) {
            if (this.numHit > 2) return true;
        }
        return false;
    },

    //着弾エフェクト
    addImpact: function(x, y) {
        var p = tm.display.AnimationSprite(tmapp.SpriteSheet.Impact)
            .addChildTo(this)
            .setPosition(x, y)
            .setScale(2)
            .gotoAndPlay("impact");
        p.onanimationend = function() {
            this.remove();
        }
    },

    //ターゲット当り判定
    checkCollision: function(x, y) {
        var list = this.mainLayer.children;
        var hit = false;
        list.forEach(function(e, i, a) {
            if (!hit && e.isHitPoint(x, y)) {
                if (e.damage(x, y)) this.numHit++;
            }
        }.bind(this));
    },

    //ゲームオーバー
    gameover: function() {
    },

    ontouchstart: function(e) {
        if (this.startGame && !this.stopTimer) {
            if (this.leftBullet > 0) {
                this.leftBullet--;
                appMain.playSE("bang");
                this.addImpact(e.pointing.x, e.pointing.y);
                this.checkCollision(e.pointing.x, e.pointing.y);
            } else {
                appMain.playSE("bang");
            }
        }
    },

    ontouchmove: function(e) {
    },

    ontouchend: function(e) {
    },
});

<|endoftext|>


<commit_before>/**
 * @license Copyright (c) CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.html or http://ckeditor.com/license
 */

(function() {
    if (!supportsLocalStorage()) {
        CKEDITOR.plugins.add("autosave", {}); //register a dummy plugin to pass CKEditor plugin initialization process
        return;
    }

    CKEDITOR.plugins.add("autosave", {
        lang: 'ca,de,en,es,jp,pl,pt-br,sv,zh,zh-cn', // %REMOVE_LINE_CORE%
        version: 0.10,
        init: function(editor) {
            CKEDITOR.document.appendStyleSheet(CKEDITOR.getUrl(CKEDITOR.plugins.getPath('autosave') + 'css/autosave.min.css'));

            if (typeof (jQuery) === 'undefined') {
                CKEDITOR.scriptLoader.load('//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js', function() {
                    jQuery.noConflict();

                    loadPlugin(editor);
                });

            } else {
                CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(CKEDITOR.plugins.getPath('autosave') + 'js/extensions.min.js'), function() {
                    loadPlugin(editor);
                });
            }
        }
    });

    function loadPlugin(editorInstance) {
        var autoSaveKey = editorInstance.config.autosave_SaveKey != null ? editorInstance.config.autosave_SaveKey : 'autosave_' + window.location;
        var notOlderThan = editorInstance.config.autosave_NotOlderThan != null ? editorInstance.config.autosave_NotOlderThan : 1440;
        var saveOnDestroy = editorInstance.config.autosave_saveOnDestroy != null ? editorInstance.config.autosave_saveOnDestroy : false;
        var saveDetectionSelectors =
            editorInstance.config.autosave_saveDetectionSelectors != null ? editorInstance.config.autosave_saveDetectionSelectors : "a[href^='javascript:__doPostBack'][id*='Save'],a[id*='Cancel']";

        CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(CKEDITOR.plugins.getPath('autosave') + 'js/extensions.min.js'), function() {
            GenerateAutoSaveDialog(editorInstance, autoSaveKey);

            CheckForAutoSavedContent(editorInstance, autoSaveKey, notOlderThan);
        });

        jQuery(saveDetectionSelectors).click(function() {
            RemoveStorage(autoSaveKey);
        });

        editorInstance.on('change', startTimer);

        editorInstance.on('destroy', function() {
            if (saveOnDestroy) {
                SaveData(autoSaveKey, editorInstance);
            }
        });

        editorInstance.on('uiSpace', function(event) {
            if (event.data.space == 'bottom') {
                event.data.html += '

'
                    + event.editor.lang.autosave.autoSaveMessage
                    + '

';
            }
        }, editorInstance, null, 100);
    }

    function autoSaveMessageId(editorInstance) {
        return 'cke_autoSaveMessage_' + editorInstance.name;
    }

    var timeOutId = 0,
        savingActive = false;

    var startTimer = function(event) {
        if (timeOutId) {
            clearTimeout(timeOutId);
        }
        var delay = CKEDITOR.config.autosave_delay != null ? CKEDITOR.config.autosave_delay : 10;
        timeOutId = setTimeout(onTimer, delay * 1000, event);
    };
    var onTimer = function(event) {
        if (savingActive) {
            startTimer(event);
        } else if (event.editor.checkDirty() || event.editor.plugins.bbcode) {
            savingActive = true;
            var editor = event.editor,
                autoSaveKey = editor.config.autosave_SaveKey != null ? editor.config.autosave_SaveKey : 'autosave_' + window.location;

            SaveData(autoSaveKey, editor);

            savingActive = false;
        }
    };

    // localStorage detection
    function supportsLocalStorage() {
        if (typeof (Storage) === 'undefined') {
            return false;
        }

        try {
            localStorage.getItem("___test_key");
            return true;
        } catch (e) {
            return false;
        }
    }

    function GenerateAutoSaveDialog(editorInstance, autoSaveKey) {
        CKEDITOR.dialog.add('autosaveDialog', function() {
            return {
                title: editorInstance.lang.autosave.title,
                minHeight: 155,
                height: 300,
                width: 750,
                onShow: function() {
                    RenderDiff(this, editorInstance, autoSaveKey);
                },
                onOk: function() {
                    var jsonSavedContent = LoadData(autoSaveKey);

                    editorInstance.setData(jsonSavedContent.data);

                    RemoveStorage(autoSaveKey);
                },
                onCancel: function() {
                    RemoveStorage(autoSaveKey);
                },
                contents: [
                    {
                        label: '',
                        id: 'general',
                        elements: [
                            {
                                type: 'radio',
                                id: 'diffType',
                                label: editorInstance.lang.autosave.diffType,
                                items: [[editorInstance.lang.autosave.sideBySide, 'sideBySide'], [editorInstance.lang.autosave.inline, 'inline']],
                                'default': 'sideBySide',
                                onClick: function() {
                                    RenderDiff(this._.dialog, editorInstance, autoSaveKey);
                                }
                            }, {
                                type: 'html',
                                id: 'diffContent',
                                html: ''
                            }
                        ]
                    }
                ],
                buttons: [
                    {
                        id: 'ok',
                        type: 'button',
                        label: editorInstance.lang.autosave.ok,
                        'class': 'cke_dialog_ui_button_ok cke_dialog_autosave_ok',
                        onClick: function(evt) {
                            var dialog = evt.data.dialog;
                            if (dialog.fire('ok', { hide: true }).hide !== false)
                                dialog.hide();
                        }
                    },
                    {
                        id: 'cancel',
                        type: 'button',
                        label: editorInstance.lang.autosave.no,
                        'class': 'cke_dialog_ui_button_cancel',
                        onClick: function(evt) {
                            var dialog = evt.data.dialog;
                            if (dialog.fire('cancel', { hide: true }).hide !== false)
                                dialog.hide();
                        }
                    }
                ]
            };
        });
    }

    function CheckForAutoSavedContent(editorInstance, autoSaveKey, notOlderThan) {
        // Checks If there is data available and load it
        if (localStorage.getItem(autoSaveKey)) {
            var jsonSavedContent = LoadData(autoSaveKey);

            var autoSavedContent = jsonSavedContent.data;
            var autoSavedContentDate = jsonSavedContent.saveTime;

            var editorLoadedContent = editorInstance.getData();

            // check if the loaded editor content is the same as the autosaved content
            if (editorLoadedContent == autoSavedContent) {
                localStorage.removeItem(autoSaveKey);
                return;
            }

            // Ignore if autosaved content is older then x minutes
            if (moment(new Date()).diff(autoSavedContentDate, 'minutes') > notOlderThan) {
                RemoveStorage(autoSaveKey);

                return;
            }

            var confirmMessage = editorInstance.lang.autosave.loadSavedContent.replace("{0}", moment(autoSavedContentDate).lang(editorInstance.config.language).format(editorInstance.lang.autosave.dateFormat));
            if (confirm(confirmMessage)) {
                // Open DIFF Dialog
                editorInstance.openDialog('autosaveDialog');
            } else {
                RemoveStorage(autoSaveKey);
            }
        }
    }

    function LoadData(autoSaveKey) {
        var compressedJSON = LZString.decompressFromUTF16(localStorage.getItem(autoSaveKey));
        return JSON.parse(compressedJSON);
    }

    function SaveData(autoSaveKey, editorInstance) {
        var compressedJSON = LZString.compressToUTF16(JSON.stringify({ data: editorInstance.getData(), saveTime: new Date() }));
        localStorage.setItem(autoSaveKey, compressedJSON);

        var autoSaveMessage = document.getElementById(autoSaveMessageId(editorInstance));

        if (autoSaveMessage) {
            autoSaveMessage.className = "show";

            setTimeout(function() {
                autoSaveMessage.className = "hidden";
            }, 2000);
        }
    }

    function RemoveStorage(autoSaveKey) {
        if (timeOutId) {
            clearTimeout(timeOutId);
        }

        localStorage.removeItem(autoSaveKey);
    }

    function RenderDiff(dialog, editorInstance, autoSaveKey) {
        var jsonSavedContent = LoadData(autoSaveKey);

        var base = difflib.stringAsLines(editorInstance.getData());
        var newtxt = difflib.stringAsLines(jsonSavedContent.data);
        var sm = new difflib.SequenceMatcher(base, newtxt);
        var opcodes = sm.get_opcodes();

        dialog.getContentElement('general', 'diffContent').getElement().setHtml('
' + diffview.buildView({
            baseTextLines: base,
            newTextLines: newtxt,
            opcodes: opcodes,
            baseTextName: editorInstance.lang.autosave.loadedContent,
            newTextName: editorInstance.lang.autosave.autoSavedContent + (moment(jsonSavedContent.saveTime).lang(editorInstance.config.language).format(editorInstance.lang.autosave.dateFormat)) + '\'',
            contextSize: 3,
            viewType: dialog.getContentElement('general', 'diffType').getValue() == "inline" ? 1 : 0
        }).outerHTML + '
');
    }
})();
<commit_msg>fix for #29<commit_after>/**
 * @license Copyright (c) CKSource - Frederico Knabben. All rights reserved.
 * For licensing, see LICENSE.html or http://ckeditor.com/license
 */

(function() {
    if (!supportsLocalStorage()) {
        CKEDITOR.plugins.add("autosave", {}); //register a dummy plugin to pass CKEditor plugin initialization process
        return;
    }

    CKEDITOR.plugins.add("autosave", {
        lang: 'ca,de,en,es,jp,pl,pt-br,sv,zh,zh-cn', // %REMOVE_LINE_CORE%
        version: 0.10,
        init: function(editor) {
            CKEDITOR.document.appendStyleSheet(CKEDITOR.getUrl(CKEDITOR.plugins.getPath('autosave') + 'css/autosave.min.css'));

            if (typeof (jQuery) === 'undefined') {
                CKEDITOR.scriptLoader.load('//ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js', function() {
                    jQuery.noConflict();

                    loadPlugin(editor);
                });

            } else {
                CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(CKEDITOR.plugins.getPath('autosave') + 'js/extensions.min.js'), function() {
                    loadPlugin(editor);
                });
            }
        }
    });

    function loadPlugin(editorInstance) {
        var autoSaveKey = editorInstance.config.autosave_SaveKey != null ? editorInstance.config.autosave_SaveKey : 'autosave_' + window.location + "_" + editorInstance.id;
        var notOlderThan = editorInstance.config.autosave_NotOlderThan != null ? editorInstance.config.autosave_NotOlderThan : 1440;
        var saveOnDestroy = editorInstance.config.autosave_saveOnDestroy != null ? editorInstance.config.autosave_saveOnDestroy : false;
        var saveDetectionSelectors =
            editorInstance.config.autosave_saveDetectionSelectors != null ? editorInstance.config.autosave_saveDetectionSelectors : "a[href^='javascript:__doPostBack'][id*='Save'],a[id*='Cancel']";

        CKEDITOR.scriptLoader.load(CKEDITOR.getUrl(CKEDITOR.plugins.getPath('autosave') + 'js/extensions.min.js'), function() {
            GenerateAutoSaveDialog(editorInstance, autoSaveKey);

            CheckForAutoSavedContent(editorInstance, autoSaveKey, notOlderThan);
        });

        jQuery(saveDetectionSelectors).click(function() {
            RemoveStorage(autoSaveKey);
        });

        editorInstance.on('change', startTimer);

        editorInstance.on('destroy', function() {
            if (saveOnDestroy) {
                SaveData(autoSaveKey, editorInstance);
            }
        });

        editorInstance.on('uiSpace', function(event) {
            if (event.data.space == 'bottom') {
                event.data.html += '

'
                    + event.editor.lang.autosave.autoSaveMessage
                    + '

';
            }
        }, editorInstance, null, 100);
    }

    function autoSaveMessageId(editorInstance) {
        return 'cke_autoSaveMessage_' + editorInstance.name;
    }

    var timeOutId = 0,
        savingActive = false;

    var startTimer = function(event) {
        if (timeOutId) {
            clearTimeout(timeOutId);
        }
        var delay = CKEDITOR.config.autosave_delay != null ? CKEDITOR.config.autosave_delay : 10;
        timeOutId = setTimeout(onTimer, delay * 1000, event);
    };
    var onTimer = function(event) {
        if (savingActive) {
            startTimer(event);
        } else if (event.editor.checkDirty() || event.editor.plugins.bbcode) {
            savingActive = true;
            var editor = event.editor,
                autoSaveKey = editor.config.autosave_SaveKey != null ? editor.config.autosave_SaveKey : 'autosave_' + window.location + "_" + editorInstance.id;

            SaveData(autoSaveKey, editor);

            savingActive = false;
        }
    };

    // localStorage detection
    function supportsLocalStorage() {
        if (typeof (Storage) === 'undefined') {
            return false;
        }

        try {
            localStorage.getItem("___test_key");
            return true;
        } catch (e) {
            return false;
        }
    }

    function GenerateAutoSaveDialog(editorInstance, autoSaveKey) {
        CKEDITOR.dialog.add('autosaveDialog', function() {
            return {
                title: editorInstance.lang.autosave.title,
                minHeight: 155,
                height: 300,
                width: 750,
                onShow: function() {
                    RenderDiff(this, editorInstance, autoSaveKey);
                },
                onOk: function() {
                    var jsonSavedContent = LoadData(autoSaveKey);

                    editorInstance.setData(jsonSavedContent.data);

                    RemoveStorage(autoSaveKey);
                },
                onCancel: function() {
                    RemoveStorage(autoSaveKey);
                },
                contents: [
                    {
                        label: '',
                        id: 'general',
                        elements: [
                            {
                                type: 'radio',
                                id: 'diffType',
                                label: editorInstance.lang.autosave.diffType,
                                items: [[editorInstance.lang.autosave.sideBySide, 'sideBySide'], [editorInstance.lang.autosave.inline, 'inline']],
                                'default': 'sideBySide',
                                onClick: function() {
                                    RenderDiff(this._.dialog, editorInstance, autoSaveKey);
                                }
                            }, {
                                type: 'html',
                                id: 'diffContent',
                                html: ''
                            }
                        ]
                    }
                ],
                buttons: [
                    {
                        id: 'ok',
                        type: 'button',
                        label: editorInstance.lang.autosave.ok,
                        'class': 'cke_dialog_ui_button_ok cke_dialog_autosave_ok',
                        onClick: function(evt) {
                            var dialog = evt.data.dialog;
                            if (dialog.fire('ok', { hide: true }).hide !== false)
                                dialog.hide();
                        }
                    },
                    {
                        id: 'cancel',
                        type: 'button',
                        label: editorInstance.lang.autosave.no,
                        'class': 'cke_dialog_ui_button_cancel',
                        onClick: function(evt) {
                            var dialog = evt.data.dialog;
                            if (dialog.fire('cancel', { hide: true }).hide !== false)
                                dialog.hide();
                        }
                    }
                ]
            };
        });
    }

    function CheckForAutoSavedContent(editorInstance, autoSaveKey, notOlderThan) {
        // Checks If there is data available and load it
        if (localStorage.getItem(autoSaveKey)) {
            var jsonSavedContent = LoadData(autoSaveKey);

            var autoSavedContent = jsonSavedContent.data;
            var autoSavedContentDate = jsonSavedContent.saveTime;

            var editorLoadedContent = editorInstance.getData();

            // check if the loaded editor content is the same as the autosaved content
            if (editorLoadedContent == autoSavedContent) {
                localStorage.removeItem(autoSaveKey);
                return;
            }

            // Ignore if autosaved content is older then x minutes
            if (moment(new Date()).diff(autoSavedContentDate, 'minutes') > notOlderThan) {
                RemoveStorage(autoSaveKey);

                return;
            }

            var confirmMessage = editorInstance.lang.autosave.loadSavedContent.replace("{0}", moment(autoSavedContentDate).lang(editorInstance.config.language).format(editorInstance.lang.autosave.dateFormat));
            if (confirm(confirmMessage)) {
                // Open DIFF Dialog
                editorInstance.openDialog('autosaveDialog');
            } else {
                RemoveStorage(autoSaveKey);
            }
        }
    }

    function LoadData(autoSaveKey) {
        var compressedJSON = LZString.decompressFromUTF16(localStorage.getItem(autoSaveKey));
        return JSON.parse(compressedJSON);
    }

    function SaveData(autoSaveKey, editorInstance) {
        var compressedJSON = LZString.compressToUTF16(JSON.stringify({ data: editorInstance.getData(), saveTime: new Date() }));
        localStorage.setItem(autoSaveKey, compressedJSON);

        var autoSaveMessage = document.getElementById(autoSaveMessageId(editorInstance));

        if (autoSaveMessage) {
            autoSaveMessage.className = "show";

            setTimeout(function() {
                autoSaveMessage.className = "hidden";
            }, 2000);
        }
    }

    function RemoveStorage(autoSaveKey) {
        if (timeOutId) {
            clearTimeout(timeOutId);
        }

        localStorage.removeItem(autoSaveKey);
    }

    function RenderDiff(dialog, editorInstance, autoSaveKey) {
        var jsonSavedContent = LoadData(autoSaveKey);

        var base = difflib.stringAsLines(editorInstance.getData());
        var newtxt = difflib.stringAsLines(jsonSavedContent.data);
        var sm = new difflib.SequenceMatcher(base, newtxt);
        var opcodes = sm.get_opcodes();

        dialog.getContentElement('general', 'diffContent').getElement().setHtml('
' + diffview.buildView({
            baseTextLines: base,
            newTextLines: newtxt,
            opcodes: opcodes,
            baseTextName: editorInstance.lang.autosave.loadedContent,
            newTextName: editorInstance.lang.autosave.autoSavedContent + (moment(jsonSavedContent.saveTime).lang(editorInstance.config.language).format(editorInstance.lang.autosave.dateFormat)) + '\'',
            contextSize: 3,
            viewType: dialog.getContentElement('general', 'diffType').getValue() == "inline" ? 1 : 0
        }).outerHTML + '
');
    }
})();
<|endoftext|>


<commit_before>// https://github.com/shelljs/shelljs
require('./check-versions')()
require('shelljs/global')
env.NODE_ENV = 'production'

var path = require('path')
var config = require('../config')
var ora = require('ora')
var webpack = require('webpack')
var webpackConfig = require('./webpack.prod.conf')

console.log(
  '  Tip:\n' +
  '  Built files are meant to be served over an HTTP server.\n' +
  '  Opening index.html over file:// won\'t work.\n'
)

var spinner = ora('building for production...')
spinner.start()

var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
rm('-rf', assetsPath)
mkdir('-p', assetsPath)
cp('-R', 'public/*', assetsPath)

webpack(webpackConfig, function (err, stats) {
  spinner.stop()
  if (err) throw err
  process.stdout.write(stats.toString({
    colors: true,
    modules: false,
    children: false,
    chunks: false,
    chunkModules: false
  }) + '\n')
})
<commit_msg>Remove local server info from build script<commit_after>// https://github.com/shelljs/shelljs
require('./check-versions')()
require('shelljs/global')
env.NODE_ENV = 'production'

var path = require('path')
var config = require('../config')
var ora = require('ora')
var webpack = require('webpack')
var webpackConfig = require('./webpack.prod.conf')

var spinner = ora('building for production...')
spinner.start()

var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
rm('-rf', assetsPath)
mkdir('-p', assetsPath)
cp('-R', 'public/*', assetsPath)

webpack(webpackConfig, function (err, stats) {
  spinner.stop()
  if (err) throw err
  process.stdout.write(stats.toString({
    colors: true,
    modules: false,
    children: false,
    chunks: false,
    chunkModules: false
  }) + '\n')
})
<|endoftext|>


<commit_before>//= require bubble
//= require postFactlinkObject
//= require_tree ./frontend
//= require factlink.backbone
//= require tour
<commit_msg>Removed another old reference<commit_after>//= require bubble
//= require postFactlinkObject
//= require_tree ./frontend
//= require factlink.backbone
<|endoftext|>


<commit_before>
// Set up inheritance structures for value objects
// see http://directwebremoting.org/dwr/documentation/server/configuration/dwrxml/converters/bean.html#interfacesAndAbstractClasses

DatabaseBackedExpressionExperimentSetValueObject.prototype = new ExpressionExperimentSetValueObject();
DatabaseBackedExpressionExperimentSetValueObject.prototype.constructor = DatabaseBackedExpressionExperimentSetValueObject;

SessionBoundExpressionExperimentSetValueObject.prototype = new ExpressionExperimentSetValueObject();
SessionBoundExpressionExperimentSetValueObject.prototype.constructor = SessionBoundExpressionExperimentSetValueObject;

FreeTextExpressionExperimentResultsValueObject.prototype = new SessionBoundExpressionExperimentSetValueObject();
FreeTextExpressionExperimentResultsValueObject.prototype.constructor = FreeTextExpressionExperimentResultsValueObject;

DatabaseBackedGeneSetValueObject.prototype = new GeneSetValueObject();
DatabaseBackedGeneSetValueObject.prototype.constructor = DatabaseBackedGeneSetValueObject;

SessionBoundGeneSetValueObject.prototype = new GeneSetValueObject();
SessionBoundGeneSetValueObject.prototype.constructor = SessionBoundGeneSetValueObject;

FreeTextGeneResultsValueObject.prototype = new SessionBoundGeneSetValueObject();
FreeTextGeneResultsValueObject.prototype.constructor = FreeTextGeneResultsValueObject;

GOGroupValueObject.prototype = new SessionBoundGeneSetValueObject();
GOGroupValueObject.prototype.constructor = FreeTextGeneResultsValueObject;
<commit_msg>Corrected the line from   GOGroupValueObject.prototype.constructor = FreeTextGeneResultsValueObject; to   GOGroupValueObject.prototype.constructor = GOGroupValueObject;<commit_after>
// Set up inheritance structures for value objects
// see http://directwebremoting.org/dwr/documentation/server/configuration/dwrxml/converters/bean.html#interfacesAndAbstractClasses

DatabaseBackedExpressionExperimentSetValueObject.prototype = new ExpressionExperimentSetValueObject();
DatabaseBackedExpressionExperimentSetValueObject.prototype.constructor = DatabaseBackedExpressionExperimentSetValueObject;

SessionBoundExpressionExperimentSetValueObject.prototype = new ExpressionExperimentSetValueObject();
SessionBoundExpressionExperimentSetValueObject.prototype.constructor = SessionBoundExpressionExperimentSetValueObject;

FreeTextExpressionExperimentResultsValueObject.prototype = new SessionBoundExpressionExperimentSetValueObject();
FreeTextExpressionExperimentResultsValueObject.prototype.constructor = FreeTextExpressionExperimentResultsValueObject;

DatabaseBackedGeneSetValueObject.prototype = new GeneSetValueObject();
DatabaseBackedGeneSetValueObject.prototype.constructor = DatabaseBackedGeneSetValueObject;

SessionBoundGeneSetValueObject.prototype = new GeneSetValueObject();
SessionBoundGeneSetValueObject.prototype.constructor = SessionBoundGeneSetValueObject;

FreeTextGeneResultsValueObject.prototype = new SessionBoundGeneSetValueObject();
FreeTextGeneResultsValueObject.prototype.constructor = FreeTextGeneResultsValueObject;

GOGroupValueObject.prototype = new SessionBoundGeneSetValueObject();
GOGroupValueObject.prototype.constructor = GOGroupValueObject;
<|endoftext|>


<commit_before>/**
 * Created by Obscurity on 2016/5/28.
 */

var show = function *(next) {
    var Article = global.database.models.article;
    var Comment = global.database.models.comment;
    var setReadSession = function (session, article) {
        if (!session.read_history) {
            session.read_history = {};
        }
        article.read_count += 1;
        article.save();
        session.read_history[article._id] = true;
    };
    var article = yield Article.findById(this.params.article_id);
    if (!this.session.read_history || !this.session.read_history[article._id]) {
        setReadSession(this.session, article);
    }
    var comments = yield Comment.find({article_id: article._id}).sort({created_at: 1});
    this.render('./columns/articles/show',{"title":article.title, article: article, comments: comments, current_user: this.session.user, current_module: this.current_module, redirect_url: this.request.url}, true);
};

var init = function *(next) {
    var Column = global.database.models.column;
    var column = yield Column.findById(this.params.column_id);
    this.render('./columns/articles/new',{"title":"写专栏文章", current_user: this.session.user, column: column, redirect_url: this.request.url}, true);
};

var create = function *(next) {
    var Article = global.database.models.article;
    var Column = global.database.models.column;
    var article = new Article();
    var column = yield Column.findById(this.params.column_id);
    article.title = this.request.body.title;
    article.order = this.request.body.order;
    article.column_id = this.params.column_id;
    article.content = !this.request.body.content ? "" : this.request.body.content;
    article.save();
    column.updated_at = Date.now();
    column.save();
    this.redirect(this.app.url("articles-detail", {column_id: this.params.column_id, article_id: article._id}));
};

var edit = function *(next) {
    var Article = global.database.models.article;
    var article = yield Article.findById(this.params.article_id);
    this.render('./columns/articles/edit',{"title": "编辑博客", article: article, current_user: this.session.user, current_module: this.current_module, redirect_url: this.request.url}, true);
};

var update = function *(next) {
    var Article = global.database.models.article;
    var Column = global.database.models.column;
    var article = yield Article.findById(this.params.article_id);
    var column = yield Column.findById(this.params.column_id);
    article.title = this.request.body.title;
    article.content = !this.request.body.content ? "" : this.request.body.content;
    article.order = this.request.body.order;
    article.column_id = this.params.column_id;
    article.updated_at = Date.now();
    article.save();
    column.updated_at = Date.now();
    column.save();
    this.redirect(this.app.url('articles-detail', {column_id: this.params.column_id, article_id: article._id}));
};

var destroy = function *(next) {
    var Article = global.database.models.article;
    var Comment = global.database.models.comment;
    var article = yield Article.findById(this.params.article_id);
    yield Comment.remove({journal_id: article._id});
    article.remove();
    this.redirect(this.app.url('columns-detail', {column_id: this.params.column_id}));
};

module.exports = {
    show: show,
    init: init,
    create: create,
    edit: edit,
    update: update,
    destroy: destroy,
    comment: require('./comments')
};<commit_msg>修正在新增专栏文章页面上导航栏中专栏一项非焦点的错误<commit_after>/**
 * Created by Obscurity on 2016/5/28.
 */

var show = function *(next) {
    var Article = global.database.models.article;
    var Comment = global.database.models.comment;
    var setReadSession = function (session, article) {
        if (!session.read_history) {
            session.read_history = {};
        }
        article.read_count += 1;
        article.save();
        session.read_history[article._id] = true;
    };
    var article = yield Article.findById(this.params.article_id);
    if (!this.session.read_history || !this.session.read_history[article._id]) {
        setReadSession(this.session, article);
    }
    var comments = yield Comment.find({article_id: article._id}).sort({created_at: 1});
    this.render('./columns/articles/show',{"title":article.title, article: article, comments: comments, current_user: this.session.user, current_module: this.current_module, redirect_url: this.request.url}, true);
};

var init = function *(next) {
    var Column = global.database.models.column;
    var column = yield Column.findById(this.params.column_id);
    this.render('./columns/articles/new',{"title":"写专栏文章", current_module: this.current_module, current_user: this.session.user, column: column, redirect_url: this.request.url}, true);
};

var create = function *(next) {
    var Article = global.database.models.article;
    var Column = global.database.models.column;
    var article = new Article();
    var column = yield Column.findById(this.params.column_id);
    article.title = this.request.body.title;
    article.order = this.request.body.order;
    article.column_id = this.params.column_id;
    article.content = !this.request.body.content ? "" : this.request.body.content;
    article.save();
    column.updated_at = Date.now();
    column.save();
    this.redirect(this.app.url("articles-detail", {column_id: this.params.column_id, article_id: article._id}));
};

var edit = function *(next) {
    var Article = global.database.models.article;
    var article = yield Article.findById(this.params.article_id);
    this.render('./columns/articles/edit',{"title": "编辑博客", article: article, current_user: this.session.user, current_module: this.current_module, redirect_url: this.request.url}, true);
};

var update = function *(next) {
    var Article = global.database.models.article;
    var Column = global.database.models.column;
    var article = yield Article.findById(this.params.article_id);
    var column = yield Column.findById(this.params.column_id);
    article.title = this.request.body.title;
    article.content = !this.request.body.content ? "" : this.request.body.content;
    article.order = this.request.body.order;
    article.column_id = this.params.column_id;
    article.updated_at = Date.now();
    article.save();
    column.updated_at = Date.now();
    column.save();
    this.redirect(this.app.url('articles-detail', {column_id: this.params.column_id, article_id: article._id}));
};

var destroy = function *(next) {
    var Article = global.database.models.article;
    var Comment = global.database.models.comment;
    var article = yield Article.findById(this.params.article_id);
    yield Comment.remove({journal_id: article._id});
    article.remove();
    this.redirect(this.app.url('columns-detail', {column_id: this.params.column_id}));
};

module.exports = {
    show: show,
    init: init,
    create: create,
    edit: edit,
    update: update,
    destroy: destroy,
    comment: require('./comments')
};<|endoftext|>


<commit_before>var CoreView = require('backbone/core-view');
var nodeIds = require('../../../value-objects/analysis-node-ids');
var layerColors = require('../../../data/layer-colors');
var template = require('./default-layer-analysis-view.tpl');
var analyses = require('../../../data/analyses');
var AnalysisTooltip = require('./analyses-tooltip-error');

/**
 * View for an analysis node with a single input
 *
 * this.model is expected to be a analysis-definition-node-nodel
 */
module.exports = CoreView.extend({

  tagName: 'li',
  className: 'Editor-ListAnalysis-item Editor-ListAnalysis-layer CDB-Text is-semibold CDB-Size-small js-analysis-node',
  initialize: function (opts) {
    if (!opts.layerDefinitionModel) throw new Error('layerDefinitionModel is required');
    if (!opts.analysisNode) throw new Error('analysisNode is required');

    this._layerDefinitionModel = opts.layerDefinitionModel;
    this._analysisNode = opts.analysisNode;

    this._analysisNode.on('change:status', this.render, this);
    this.add_related_model(this._analysisNode);

    AnalysisTooltip.track(this._analysisNode, this.$el, '.Editor-ListAnalysis-itemError');
  },

  render: function () {
    var status = this._analysisNode.get('status');

    this.$el.html(template({
      id: this.model.id,
      bgColor: this._bgColor(),
      isDone: status === 'ready' || status === 'failed',
      title: analyses.title(this.model),
      hasError: status === 'failed'
    }));
    this.$el.toggleClass('has-error', status === 'failed');

    this.el.dataset.analysisNodeId = this.model.id;

    return this;
  },

  _bgColor: function () {
    var letter = nodeIds.letter(this._analysisNode.id);
    return layerColors.getColorForLetter(letter);
  },

  clean: function () {
    AnalysisTooltip.destroy();
    CoreView.prototype.clean.call(this);
  }
});
<commit_msg>Class with capital, variables with lowerCase<commit_after>var CoreView = require('backbone/core-view');
var nodeIds = require('../../../value-objects/analysis-node-ids');
var layerColors = require('../../../data/layer-colors');
var template = require('./default-layer-analysis-view.tpl');
var Analyses = require('../../../data/analyses');
var AnalysisTooltip = require('./analyses-tooltip-error');

/**
 * View for an analysis node with a single input
 *
 * this.model is expected to be a analysis-definition-node-nodel
 */
module.exports = CoreView.extend({

  tagName: 'li',
  className: 'Editor-ListAnalysis-item Editor-ListAnalysis-layer CDB-Text is-semibold CDB-Size-small js-analysis-node',
  initialize: function (opts) {
    if (!opts.layerDefinitionModel) throw new Error('layerDefinitionModel is required');
    if (!opts.analysisNode) throw new Error('analysisNode is required');

    this._layerDefinitionModel = opts.layerDefinitionModel;
    this._analysisNode = opts.analysisNode;

    this._analysisNode.on('change:status', this.render, this);
    this.add_related_model(this._analysisNode);

    AnalysisTooltip.track(this._analysisNode, this.$el, '.Editor-ListAnalysis-itemError');
  },

  render: function () {
    var status = this._analysisNode.get('status');

    this.$el.html(template({
      id: this.model.id,
      bgColor: this._bgColor(),
      isDone: status === 'ready' || status === 'failed',
      title: Analyses.title(this.model),
      hasError: status === 'failed'
    }));
    this.$el.toggleClass('has-error', status === 'failed');

    this.el.dataset.analysisNodeId = this.model.id;

    return this;
  },

  _bgColor: function () {
    var letter = nodeIds.letter(this._analysisNode.id);
    return layerColors.getColorForLetter(letter);
  },

  clean: function () {
    AnalysisTooltip.destroy();
    CoreView.prototype.clean.call(this);
  }
});
<|endoftext|>