<commit_before>'use strict';

const vo = require('vo'); //generetor/yeld
const getChannelId = require('./lib/channel');
const http = require('http');
const URL = 'http://liginc.co.jp/devrel';
const TARGET_CHANNEL_NAME = 'tool';
const CronJob = require('cron').CronJob;
let last_url = '';

module.exports = (bot) => {

  new CronJob('00 00 04 * * *', () => {
    update_check();
  }, null, true, 'Asia/Tokyo');

  function update_check(){
    vo(function* (){
      let update_url = yield _fetch(); //最新記事のURLを取得
      if(last_url === update_url) return '更新無し';
      last_url = update_url;
      let id = yield getChannelId(TARGET_CHANNEL_NAME); //チャンネルID取得
      bot.say({text: '@channel DevRel記事が更新されました！'+update_url, channel: id}); //投稿
      return update_url;
    })((err, result) => {
      if (err) return console.log(err);
      console.log(result);
    });
  }

};

//最新記事を取得
function _fetch(){
  return new Promise((resolve, reject) => {
    http.get(URL, (res) => {
      let body = '';
      res.setEncoding('utf8');
      res.on('data', (chunk) => {
        body += chunk;
      });
      res.on('end', (res) => {
        let link = body.match(/
\n\t/)[1];
        if(!link) reject('parse error');
        setTimeout(() => {
          resolve(link);
        },2000);
      });
    }).on('error', (e) => {
      reject(e.message);
    });
  });
}
<commit_msg>update<commit_after>'use strict';

const vo = require('vo'); //generetor/yeld
const getChannelId = require('./lib/channel');
const http = require('http');
const URL = 'http://liginc.co.jp/devrel';
const TARGET_CHANNEL_NAME = 'zatsudan';
const CronJob = require('cron').CronJob;
let last_url = '';

module.exports = (bot) => {

  new CronJob('00 00 10 * * *', () => {
    update_check();
  }, null, true, 'Asia/Tokyo');

  function update_check(){
    vo(function* (){
      let update_url = yield _fetch(); //最新記事のURLを取得
      if(last_url === update_url) return '更新無し';
      last_url = update_url;
      let id = yield getChannelId(TARGET_CHANNEL_NAME); //チャンネルID取得
      bot.say({text: '@channel DevRel記事が更新されました！'+update_url, channel: id}); //投稿
      return update_url;
    })((err, result) => {
      if (err) return console.log(err);
      console.log(result);
    });
  }

};

//最新記事を取得
function _fetch(){
  return new Promise((resolve, reject) => {
    http.get(URL, (res) => {
      let body = '';
      res.setEncoding('utf8');
      res.on('data', (chunk) => {
        body += chunk;
      });
      res.on('end', (res) => {
        let link = body.match(/
\n\t/)[1];
        if(!link) reject('parse error');
        setTimeout(() => {
          resolve(link);
        },2000);
      });
    }).on('error', (e) => {
      reject(e.message);
    });
  });
}
<|endoftext|>


<commit_before>#!/usr/bin/env node
const child_process = require('child_process');
const fs = require('fs');
const path = require('path');
const os = require('os');
const chalk = require('chalk');
const testCases = require('./cases');

const BLINKSOCKS_PATH = path.resolve(__dirname, '../bin/start.js');
const IPERF_PATH = path.join(__dirname, 'iperf.sh');
const SEC_PER_CASE = 3;

function makeConfs(presets) {
  const serverConf = {
    "service": "tcp://localhost:1082",
    "key": "JJ9,$!.!sRG==v7$",
    "presets": presets,
    // "tls_key": "key.pem",
    // "tls_cert": "cert.pem"
    "log_level": "error"
  };
  const clientConf = {
    "service": "tcp://127.0.0.1:1081",
    // "tls_cert": "cert.pem"
    "dstaddr": {
      "host": "127.0.0.1",
      "port": 1083
    },
    "servers": [Object.assign({}, serverConf, {"enabled": true})],
    "log_level": "error"
  };
  return [clientConf, serverConf];
}

function writeConfs(caseId, presets) {
  const [clientConf, serverConf] = makeConfs(presets);
  const clientJson = path.join(__dirname, `jsons/case-${caseId}-client.json`);
  const serverJson = path.join(__dirname, `jsons/case-${caseId}-server.json`);
  fs.writeFileSync(clientJson, JSON.stringify(clientConf, null, '  '));
  fs.writeFileSync(serverJson, JSON.stringify(serverConf, null, '  '));
  return [clientJson, serverJson];
}

function parseStdout(stdout) {
  const matches = stdout.match(/\[SUM].*sec/g);
  if (matches === null) {
    console.error(stdout);
    return null;
  }
  return matches.slice(-2).map((line) => {
    const [interval, transfer, bitrate] = line.match(/\d+[.\d\-\s]+\w+[\/\w]+/g);
    return {interval, transfer, bitrate};
  });
}

function convertTransferToKBytes(transfer) {
  const [num, unit] = transfer.split(' ');
  const factor = {
    'Gbits/sec': 1024 * 1024,
    'Mbits/sec': 1024,
    'Kbits/sec': 1
  }[unit];
  return num * factor;
}

function printTestEnv() {
  console.log(chalk.bold.underline('blinksocks version:'));
  console.log(child_process.execSync(`node ${BLINKSOCKS_PATH} -v`, {encoding: 'utf-8'}).trim());
  console.log('');
  console.log(chalk.bold.underline('Operating System:'));
  const osParams = [
    ['cpu', os.cpus()[0].model],
    ['cores', os.cpus().length],
    ['memory', os.totalmem()],
    ['type', os.type()],
    ['platform', os.platform()],
    ['arch', os.arch()],
    ['release', os.release()]
  ];
  for (const [key, value] of osParams) {
    console.log('%s %s', key.padEnd(15), value);
  }
  console.log('');
  console.log(chalk.bold.underline('Node.js Versions:'));
  for (const [key, value] of Object.entries(process.versions)) {
    console.log('%s %s', key.padEnd(15), value);
  }
  console.log('');
}

function run(cases) {
  const results = [];
  for (let i = 0; i < cases.length; ++i) {
    const presets = cases[i];
    const [clientJson, serverJson] = writeConfs(i, presets);
    try {
      const stdout = child_process.execFileSync(
        IPERF_PATH, [clientJson, serverJson, SEC_PER_CASE.toString()], {encoding: 'utf-8'}
      );
      const parsed = parseStdout(stdout);
      if (parsed === null) {
        continue;
      }
      const [a, b] = parsed;
      console.log(`------------ ${chalk.green(`Test Case ${i}`)} ----------------`);
      console.log(JSON.stringify(presets));
      console.log('Interval         Transfer     Bitrate');
      console.log(`${a.interval}  ${a.transfer}  ${a.bitrate}  sender`);
      console.log(`${b.interval}  ${b.transfer}  ${b.bitrate}  receiver`);
      console.log('-----------------------------------------');
      console.log('');
      const conv = convertTransferToKBytes;
      results.push({
        id: i,
        bitrates: [a.bitrate, b.bitrate],
        recvBitrate: conv(b.bitrate),
        conf: JSON.stringify(presets)
      });
    } catch (err) {
      console.error(err);
    }
  }
  return results;
}

function summary(results) {
  const sorted = [].concat(results).sort((a, b) => b.recvBitrate - a.recvBitrate);
  console.log('(ranking):');
  console.log('');
  for (let i = 0; i < sorted.length; ++i) {
    const {id, bitrates, conf} = sorted[i];
    console.log(`${(i + 1).toString().padStart(2)}: Test Case ${id}, Bitrate = ${bitrates.join(', ')}`);
    console.log(`    ${conf}`);
  }
  console.log('');
}

printTestEnv();

console.log(`running ${testCases.length} tests...`);
console.log('');

summary(run(testCases));
<commit_msg>benchmark: use "?forward" instead of "dstaddr"<commit_after>#!/usr/bin/env node
const child_process = require('child_process');
const fs = require('fs');
const path = require('path');
const os = require('os');
const chalk = require('chalk');
const testCases = require('./cases');

const BLINKSOCKS_PATH = path.resolve(__dirname, '../bin/start.js');
const IPERF_PATH = path.join(__dirname, 'iperf.sh');
const SEC_PER_CASE = 3;

function makeConfs(presets) {
  const serverConf = {
    "service": "tcp://localhost:1082",
    "key": "JJ9,$!.!sRG==v7$",
    "presets": presets,
    // "tls_key": "key.pem",
    // "tls_cert": "cert.pem"
    "log_level": "error"
  };
  const clientConf = {
    "service": "tcp://127.0.0.1:1081?forward=127.0.0.1:1083",
    // "tls_cert": "cert.pem"
    "servers": [Object.assign({}, serverConf, {"enabled": true})],
    "log_level": "error"
  };
  return [clientConf, serverConf];
}

function writeConfs(caseId, presets) {
  const [clientConf, serverConf] = makeConfs(presets);
  const clientJson = path.join(__dirname, `jsons/case-${caseId}-client.json`);
  const serverJson = path.join(__dirname, `jsons/case-${caseId}-server.json`);
  fs.writeFileSync(clientJson, JSON.stringify(clientConf, null, '  '));
  fs.writeFileSync(serverJson, JSON.stringify(serverConf, null, '  '));
  return [clientJson, serverJson];
}

function parseStdout(stdout) {
  const matches = stdout.match(/\[SUM].*sec/g);
  if (matches === null) {
    console.error(stdout);
    return null;
  }
  return matches.slice(-2).map((line) => {
    const [interval, transfer, bitrate] = line.match(/\d+[.\d\-\s]+\w+[\/\w]+/g);
    return {interval, transfer, bitrate};
  });
}

function convertTransferToKBytes(transfer) {
  const [num, unit] = transfer.split(' ');
  const factor = {
    'Gbits/sec': 1024 * 1024,
    'Mbits/sec': 1024,
    'Kbits/sec': 1
  }[unit];
  return num * factor;
}

function printTestEnv() {
  console.log(chalk.bold.underline('blinksocks version:'));
  console.log(child_process.execSync(`node ${BLINKSOCKS_PATH} -v`, {encoding: 'utf-8'}).trim());
  console.log('');
  console.log(chalk.bold.underline('Operating System:'));
  const osParams = [
    ['cpu', os.cpus()[0].model],
    ['cores', os.cpus().length],
    ['memory', os.totalmem()],
    ['type', os.type()],
    ['platform', os.platform()],
    ['arch', os.arch()],
    ['release', os.release()]
  ];
  for (const [key, value] of osParams) {
    console.log('%s %s', key.padEnd(15), value);
  }
  console.log('');
  console.log(chalk.bold.underline('Node.js Versions:'));
  for (const [key, value] of Object.entries(process.versions)) {
    console.log('%s %s', key.padEnd(15), value);
  }
  console.log('');
}

function run(cases) {
  const results = [];
  for (let i = 0; i < cases.length; ++i) {
    const presets = cases[i];
    const [clientJson, serverJson] = writeConfs(i, presets);
    try {
      const stdout = child_process.execFileSync(
        IPERF_PATH, [clientJson, serverJson, SEC_PER_CASE.toString()], {encoding: 'utf-8'}
      );
      const parsed = parseStdout(stdout);
      if (parsed === null) {
        continue;
      }
      const [a, b] = parsed;
      console.log(`------------ ${chalk.green(`Test Case ${i}`)} ----------------`);
      console.log(JSON.stringify(presets));
      console.log('Interval         Transfer     Bitrate');
      console.log(`${a.interval}  ${a.transfer}  ${a.bitrate}  sender`);
      console.log(`${b.interval}  ${b.transfer}  ${b.bitrate}  receiver`);
      console.log('-----------------------------------------');
      console.log('');
      const conv = convertTransferToKBytes;
      results.push({
        id: i,
        bitrates: [a.bitrate, b.bitrate],
        recvBitrate: conv(b.bitrate),
        conf: JSON.stringify(presets)
      });
    } catch (err) {
      console.error(err);
    }
  }
  return results;
}

function summary(results) {
  const sorted = [].concat(results).sort((a, b) => b.recvBitrate - a.recvBitrate);
  console.log('(ranking):');
  console.log('');
  for (let i = 0; i < sorted.length; ++i) {
    const {id, bitrates, conf} = sorted[i];
    console.log(`${(i + 1).toString().padStart(2)}: Test Case ${id}, Bitrate = ${bitrates.join(', ')}`);
    console.log(`    ${conf}`);
  }
  console.log('');
}

printTestEnv();

console.log(`running ${testCases.length} tests...`);
console.log('');

summary(run(testCases));
<|endoftext|>


<commit_before>import { mat4, vec3 } from "pex-math";
import { orbiter as createOrbiter } from "pex-cam";

const tmpMatrix = mat4.create();

export default function createCameraSystem() {
  const cameraSystem = {
    type: "camera-system",
  };

  cameraSystem.update = (entities) => {
    for (let entity of entities) {
      if (entity.camera && entity.orbiter) {
        const orbiter = entity.orbiter;
        const camera = entity.camera;
        //TODO: remove proxy and just use camera as component
        if (!orbiter._orbiter) {
          const proxyCamera = {
            viewMatrix: mat4.create(),
            position: camera.position,
            target: camera.target,
            set({ position }) {
              vec3.set(camera.position, position);
              vec3.set(entity.transform.position, position);
              entity.transform = {
                ...entity.transform,
              };
            },
          };
          orbiter._orbiter = createOrbiter({
            element: entity.orbiter.element || document.body, //TODO: element used to default to ctx.gl.canvas
            autoUpdate: false,
            camera: proxyCamera,
            position: entity.orbiter.position || [0, 0, 2.5], //TODO: orbiter position vs distance is confusing, shoudln't it come from camera anyway?
            distance: entity.orbiter.distance || 2,
          });
        } else {
          entity.orbiter._orbiter.updateCamera();
          mat4.lookAt(
            camera.viewMatrix,
            camera.position,
            camera.target,
            camera.up
          );

          mat4.set(camera.inverseViewMatrix, camera.viewMatrix);
          mat4.invert(camera.inverseViewMatrix);
        }
      }
    }
  };
  return cameraSystem;
}
<commit_msg>feat(systems/camera-system): use orbiter position if provided<commit_after>import { mat4, vec3 } from "pex-math";
import { orbiter as createOrbiter } from "pex-cam";

const tmpMatrix = mat4.create();

export default function createCameraSystem() {
  const cameraSystem = {
    type: "camera-system",
  };

  cameraSystem.update = (entities) => {
    for (let entity of entities) {
      if (entity.camera && entity.orbiter) {
        const orbiter = entity.orbiter;
        const camera = entity.camera;
        //TODO: remove proxy and just use camera as component
        if (!orbiter._orbiter) {
          const proxyCamera = {
            viewMatrix: mat4.create(),
            position: entity.orbiter.position || camera.position,
            target: camera.target,
            set({ position }) {
              vec3.set(camera.position, position);
              vec3.set(entity.transform.position, position);
              entity.transform = {
                ...entity.transform,
              };
            },
          };
          orbiter._orbiter = createOrbiter({
            element: entity.orbiter.element || document.body, //TODO: element used to default to ctx.gl.canvas
            autoUpdate: false,
            camera: proxyCamera,
            position: entity.orbiter.position || [0, 0, 2.5], //TODO: orbiter position vs distance is confusing, shoudln't it come from camera anyway?
            distance: entity.orbiter.distance || 2,
          });
        } else {
          entity.orbiter._orbiter.updateCamera();
          mat4.lookAt(
            camera.viewMatrix,
            camera.position,
            camera.target,
            camera.up
          );

          mat4.set(camera.inverseViewMatrix, camera.viewMatrix);
          mat4.invert(camera.inverseViewMatrix);
        }
      }
    }
  };
  return cameraSystem;
}
<|endoftext|>


<commit_before>var mkdirp = require('mkdirp');

mkdirp.sync('./typings/maker.js');
<commit_msg>add comment<commit_after>var mkdirp = require('mkdirp');

// synchronously execute mkdir -p
mkdirp.sync('./typings/maker.js');
<|endoftext|>


<commit_before>/*
 * FileToLessClass
 * https://github.com/chthomos/FileToLessClass
 *
 * Copyright (c) 2013 Harry Thomos
 * Licensed under the MIT license.
 */

'use strict';
var fs = require('fs');
var path = require('path');
module.exports = function(grunt) {

  grunt.registerMultiTask('filetolessclass', 'Gets all files in a directory and creates a less class for each file. Useful for sprites', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      validExtensions : ['png','jpg','gif'],    //Extensions to generate classes from
      lessSuffix : '-image',                    //Generated class suffix
      lessPrefix : '',                          //Generated class prefix
      importers : [],                           //Less imports at the beginning of each generated file
    });

    function getExtension(filename) {
      var ext = path.extname(filename||'').split('.');
      return ext[ext.length - 1];
    }

    function getName(filename) {
      var ext = path.basename(filename||'').split('.');
      return ext[0];
    }

    // Iterate over all specified file groups.
    this.files.forEach(function(f) {

      var output = "";

      //Less importing
      if (typeof(options.importers[f.dest])!='undefined'){
        if (typeof(options.importers[f.dest])=='object'){
          for(var i in options.importers[f.dest])
            if (options.importers[f.dest].hasOwnProperty(i))
              output += "@import \"" + options.importers[f.dest][i] + "\";\n"
        }
        else{
              output += "@import \"" + options.importers[f.dest] + "\";\n"
        }
        output += "\n";
      }
      var folder = f.orig.src[0];
      //Loop through files
      grunt.log.writeln("Processing folder: " + folder);
      if (fs.existsSync(folder)) {
       if (fs.lstatSync(folder).isDirectory()){
          var count =0;
          var ignored = 0;
          fs.readdirSync(folder).forEach(function(f){
            var extension = getExtension(folder + "/" + f);
            var name= "";

            if ((options.validExtensions.indexOf(extension)!=='-1')&&(!fs.lstatSync(folder + "/" + f).isDirectory())){
              //The file is valid
              count +=1;
              name = getName(f);
              output += "." + options.lessPrefix + name + options.lessSuffix + "{\t.sprite(@" + name + ");}\n";
            }        else {
              ignored +=1;
            }
          });
          grunt.file.write(f.dest,output);
          grunt.log.ok('File "' + f.dest + '" created from ' + count + ' file(s)  (ignored ' + ignored + ' files / folders)');
        }else {
          grunt.log.error(f.orig.src + ' is not a directory');
        }
      }else {
        grunt.log.error(f.orig.src + ' does not exist');
      }

    });
  });

};
<commit_msg>Fix about correctly ignoring suffixes<commit_after>/*
 * FileToLessClass
 * https://github.com/chthomos/FileToLessClass
 *
 * Copyright (c) 2013 Harry Thomos
 * Licensed under the MIT license.
 */

'use strict';
var fs = require('fs');
var path = require('path');
module.exports = function(grunt) {

  grunt.registerMultiTask('filetolessclass', 'Gets all files in a directory and creates a less class for each file. Useful for sprites', function() {
    // Merge task-specific and/or target-specific options with these defaults.
    var options = this.options({
      validExtensions : ['png','jpg','gif'],    //Extensions to generate classes from
      lessSuffix : '-image',                    //Generated class suffix
      lessPrefix : '',                          //Generated class prefix
      importers : [],                           //Less imports at the beginning of each generated file
    });

    function getExtension(filename) {
      var ext = path.extname(filename||'').split('.');
      return ext[ext.length - 1];
    }

    function getName(filename) {
      var ext = path.basename(filename||'').split('.');
      return ext[0];
    }

    // Iterate over all specified file groups.
    this.files.forEach(function(f) {

      var output = "";

      //Less importing
      if (typeof(options.importers[f.dest])!='undefined'){
        if (typeof(options.importers[f.dest])=='object'){
          for(var i in options.importers[f.dest])
            if (options.importers[f.dest].hasOwnProperty(i))
              output += "@import \"" + options.importers[f.dest][i] + "\";\n"
        }
        else{
              output += "@import \"" + options.importers[f.dest] + "\";\n"
        }
        output += "\n";
      }
      var folder = f.orig.src[0];
      //Loop through files
      grunt.log.writeln("Processing folder: " + folder);
      if (fs.existsSync(folder)) {
       if (fs.lstatSync(folder).isDirectory()){
          var count =0;
          var ignored = 0;
          fs.readdirSync(folder).forEach(function(f){
            var extension = getExtension(folder + "/" + f);
            var name= "";
            console.log(extension);
            if ((options.validExtensions.indexOf(extension)!==-1)&&(!fs.lstatSync(folder + "/" + f).isDirectory())){
              //The file is valid
              count +=1;
              name = getName(f);
              output += "." + options.lessPrefix + name + options.lessSuffix + "{\t.sprite(@" + name + ");}\n";
            }        else {
              ignored +=1;
            }
          });
          grunt.file.write(f.dest,output);
          grunt.log.ok('File "' + f.dest + '" created from ' + count + ' file(s)  (ignored ' + ignored + ' files / folders)');
        }else {
          grunt.log.error(f.orig.src + ' is not a directory');
        }
      }else {
        grunt.log.error(f.orig.src + ' does not exist');
      }

    });
  });

};
<|endoftext|>


<commit_before>/*
 * grunt-ember-templates
 *
 * Copyright (c) 2012 Dan Gebhardt, Tim Branyen, contributors
 * Licensed under the MIT license.
 * https://github.com/dgeb/grunt-ember-templates/blob/master/LICENSE
 */

function manualCompile(handlebarsPath, templateCompilerPath, template){
  'use strict';

  var fs                 = require('fs'),
      vm                 = require('vm'),
      handlebarsJs       = fs.readFileSync(handlebarsPath, 'utf8'),
      templateCompilerJs = fs.readFileSync(templateCompilerPath, 'utf8');

  // Create a context into which we will load both the ember template compiler
  // as well as the template to be compiled. The ember template compiler expects
  // `exports` to be defined, and uses it to export `precompile()`.
  var context = vm.createContext({
    module: {},
    exports: {},
    template: template
  });

  // Load handlebars
  vm.runInContext(handlebarsJs, context, 'handlebars.js');

  // Load the ember template compiler
  vm.runInContext(templateCompilerJs, context, 'ember-template-compiler.js');

  // Compile the template
  vm.runInContext('compiledJS = (module.exports || exports).precompile(template);', context);

  return context.compiledJS;
};

module.exports = function(grunt) {
  'use strict';

  var compiler = require('ember-template-compiler');
  var path = require('path');

  var writeFile = function(contents, dest, options) {
    if (options.amd) {
      contents = contents.concat('});');
    }

    if (contents.length > 0) {
      grunt.file.write(dest, contents.join('\n\n'));
      grunt.log.writeln('File "' + dest + '" created.');
    }
  };

  var emberTemplatesTask = function() {
    var options = this.options({
      templateFileExtensions: /\.(hbs|hjs|handlebars)/,
      amd: false,
      concatenate: true,
      precompile: true,
      templateName: function(name) { return name; },
      templateNameFromFile: function(file) {
        // `templateBaseDir` is an alias for `templateBasePath`
        var templateBasePath = options.templateBasePath || options.templateBaseDir;
        [templateBasePath, options.templateFileExtensions].forEach(function(match) {
          if (match) {
            file = file.replace(match, '');
          }
        });

        // Remove leading slash if necessary
        if (file.charAt(0) === '/') {
          file = file.slice(1);
        }

        return options.templateName(file);
      },
      templateRegistration: function(name, contents) {
        return 'Ember.TEMPLATES[' + JSON.stringify(name) + '] = ' + contents + ';'
      },
      handlebarsPath: null,
      templateCompilerPath: null,
      templateNamespace: 'HTMLBars'
    });

    grunt.verbose.writeflags(options, 'Options');

    // Iterate files
    this.files.forEach(function(f) {
      var processedTemplates = [],
          output = [],
          name,
          customAmd,
          contents;

      if (options.amd) {
        customAmd = typeof options.amd === 'string' && options.amd !== 'true';
        customAmd = customAmd ? options.amd : 'ember';
        output = output.concat('define(["' + customAmd + '"], function(Ember){');
      }

      f.src.forEach(function(file) {
        try {

          name = options.templateNameFromFile(file);

          if (options.precompile) {

            var template = grunt.file.read(file);
            var compiledTemplate;

            // Run the `preprocess` function if specified in the options.
            if (typeof options.preprocess === 'function') {
              template = options.preprocess(template);
            }

            if (options.handlebarsPath && options.templateCompilerPath) {
              compiledTemplate = manualCompile(options.handlebarsPath, options.templateCompilerPath, template);
            } else {
              compiledTemplate = compiler.precompile(template, false).toString();
            }

            // Wrap compiled template
            contents = 'Ember.' + options.templateNamespace + '.template(' + compiledTemplate + ')';
          } else {
            // Wrap raw (uncompiled) template
            contents = 'Ember.' + options.templateNamespace + '.compile(' + JSON.stringify(grunt.file.read(file)) + ')';
          }

          processedTemplates.push({
            name: name,
            contents: options.templateRegistration(name, contents)
          });

        } catch(e) {
          grunt.log.error(e);
          grunt.fail.warn('Ember Handlebars failed to compile ' + file + '.');
        }
      });

      if (options.concatenate) {
        // Map over the 'contents' property and concatenate
        output = output.concat(
          processedTemplates.map(function(template) {
            return template.contents;
          }));

        writeFile(output, f.dest, options);

      } else {
        // Write a file for each template
        processedTemplates.forEach(function(template) {
          writeFile(output.concat(template.contents),
                    path.join(f.dest, template.name + '.js'),
                    options);
        });
      }

    });
  };

  grunt.registerMultiTask('emberTemplates', 'Compile Handlebars templates for Ember.', emberTemplatesTask);

  // TODO: remove deprecated `ember_templates` task from v0.5
  grunt.registerMultiTask('ember_templates', 'Compile Handlebars templates for Ember. [DEPRECATED: please use `emberTemplates` instead]', function() {
    grunt.log.warn('`ember_templates` is deprecated and will be removed in v0.5. Please use `emberTemplates` instead.');
    emberTemplatesTask.apply(this, arguments);
  });
};
<commit_msg>Fix error when using with Ember.js 2.0<commit_after>/*
 * grunt-ember-templates
 *
 * Copyright (c) 2012 Dan Gebhardt, Tim Branyen, contributors
 * Licensed under the MIT license.
 * https://github.com/dgeb/grunt-ember-templates/blob/master/LICENSE
 */

function manualCompile(handlebarsPath, templateCompilerPath, template){
  'use strict';

  var fs                 = require('fs'),
      vm                 = require('vm'),
      handlebarsJs       = fs.readFileSync(handlebarsPath, 'utf8'),
      templateCompilerJs = fs.readFileSync(templateCompilerPath, 'utf8');

  // Create a context into which we will load both the ember template compiler
  // as well as the template to be compiled. The ember template compiler expects
  // `exports` to be defined, and uses it to export `precompile()`. It also
  // expects `global` to be defined and to be an object.
  var context = vm.createContext({
    module: {},
    exports: {},
    global: {},
    template: template
  });

  // Load handlebars
  vm.runInContext(handlebarsJs, context, 'handlebars.js');

  // Load the ember template compiler
  vm.runInContext(templateCompilerJs, context, 'ember-template-compiler.js');

  // Compile the template
  vm.runInContext('compiledJS = (module.exports || exports).precompile(template);', context);

  return context.compiledJS;
};

module.exports = function(grunt) {
  'use strict';

  var compiler = require('ember-template-compiler');
  var path = require('path');

  var writeFile = function(contents, dest, options) {
    if (options.amd) {
      contents = contents.concat('});');
    }

    if (contents.length > 0) {
      grunt.file.write(dest, contents.join('\n\n'));
      grunt.log.writeln('File "' + dest + '" created.');
    }
  };

  var emberTemplatesTask = function() {
    var options = this.options({
      templateFileExtensions: /\.(hbs|hjs|handlebars)/,
      amd: false,
      concatenate: true,
      precompile: true,
      templateName: function(name) { return name; },
      templateNameFromFile: function(file) {
        // `templateBaseDir` is an alias for `templateBasePath`
        var templateBasePath = options.templateBasePath || options.templateBaseDir;
        [templateBasePath, options.templateFileExtensions].forEach(function(match) {
          if (match) {
            file = file.replace(match, '');
          }
        });

        // Remove leading slash if necessary
        if (file.charAt(0) === '/') {
          file = file.slice(1);
        }

        return options.templateName(file);
      },
      templateRegistration: function(name, contents) {
        return 'Ember.TEMPLATES[' + JSON.stringify(name) + '] = ' + contents + ';'
      },
      handlebarsPath: null,
      templateCompilerPath: null,
      templateNamespace: 'HTMLBars'
    });

    grunt.verbose.writeflags(options, 'Options');

    // Iterate files
    this.files.forEach(function(f) {
      var processedTemplates = [],
          output = [],
          name,
          customAmd,
          contents;

      if (options.amd) {
        customAmd = typeof options.amd === 'string' && options.amd !== 'true';
        customAmd = customAmd ? options.amd : 'ember';
        output = output.concat('define(["' + customAmd + '"], function(Ember){');
      }

      f.src.forEach(function(file) {
        try {

          name = options.templateNameFromFile(file);

          if (options.precompile) {

            var template = grunt.file.read(file);
            var compiledTemplate;

            // Run the `preprocess` function if specified in the options.
            if (typeof options.preprocess === 'function') {
              template = options.preprocess(template);
            }

            if (options.handlebarsPath && options.templateCompilerPath) {
              compiledTemplate = manualCompile(options.handlebarsPath, options.templateCompilerPath, template);
            } else {
              compiledTemplate = compiler.precompile(template, false).toString();
            }

            // Wrap compiled template
            contents = 'Ember.' + options.templateNamespace + '.template(' + compiledTemplate + ')';
          } else {
            // Wrap raw (uncompiled) template
            contents = 'Ember.' + options.templateNamespace + '.compile(' + JSON.stringify(grunt.file.read(file)) + ')';
          }

          processedTemplates.push({
            name: name,
            contents: options.templateRegistration(name, contents)
          });

        } catch(e) {
          grunt.log.error(e);
          grunt.fail.warn('Ember Handlebars failed to compile ' + file + '.');
        }
      });

      if (options.concatenate) {
        // Map over the 'contents' property and concatenate
        output = output.concat(
          processedTemplates.map(function(template) {
            return template.contents;
          }));

        writeFile(output, f.dest, options);

      } else {
        // Write a file for each template
        processedTemplates.forEach(function(template) {
          writeFile(output.concat(template.contents),
                    path.join(f.dest, template.name + '.js'),
                    options);
        });
      }

    });
  };

  grunt.registerMultiTask('emberTemplates', 'Compile Handlebars templates for Ember.', emberTemplatesTask);

  // TODO: remove deprecated `ember_templates` task from v0.5
  grunt.registerMultiTask('ember_templates', 'Compile Handlebars templates for Ember. [DEPRECATED: please use `emberTemplates` instead]', function() {
    grunt.log.warn('`ember_templates` is deprecated and will be removed in v0.5. Please use `emberTemplates` instead.');
    emberTemplatesTask.apply(this, arguments);
  });
};
<|endoftext|>


<commit_before>import cn from 'classnames';
import invariant from 'invariant';
import React, { PropTypes } from 'react';
import elementType from 'react-prop-types/lib/elementType';

import { bsClass as setBsClass, prefix } from './utils/bootstrapUtils';

let animationPropType = PropTypes.oneOfType([
  PropTypes.bool,
  elementType
]);

let TabContent = React.createClass({

  propTypes: {

    /**
     * the Component used to render the TabContent
     */
    componentClass: elementType,

    /**
     * Sets a default animation strategy for all children TabPanes.
     * Use `false` to disable, `true` to enable the default "Fade"
     * animation or any `<Transition>` component.
     */
    animation: PropTypes.oneOfType([
      PropTypes.bool,
      elementType
    ]),
  },

  contextTypes: {
    $bs_tabcontainer: React.PropTypes.shape({
      activeKey: React.PropTypes.any,
      onSelect: PropTypes.func,
    })
  },

  childContextTypes: {
    $bs_tabcontent: PropTypes.shape({
      bsClass: PropTypes.string,
      animation: animationPropType,
      activeKey: PropTypes.any,
      onExited: PropTypes.func,
      register: PropTypes.func
    }),
  },

  getDefaultProps() {
    return {
      componentClass: 'div',
      animation: true
    };
  },

  getInitialState() {
    return {
      exitingPane: null
    };
  },

  getChildContext() {
    let exitingPane = this._exitingPane;

    return {
      $bs_tabcontent: {
        bsClass: this.props.bsClass,
        animation: this.props.animation,
        activeKey: exitingPane ? undefined : this.getActiveKey(),
        onExited: this.handlePaneExited,
        register: this.registerPane
      }
    };
  },

  /**
   * This belongs in `componentWillReceiveProps()` but
   * 0.14.x contains a bug where cwrp isn't called when only context changes.
   * fixed in master, not sure it will make it into any 0.14 release
   */
  componentWillUpdate(nextProps, _, nextContext) {
    let currentActiveKey = this.getActiveKey();
    let nextActiveKey = this.getActiveKey(nextContext);
    let currentKeyIsStillValid = this.panes.indexOf(currentActiveKey) !== -1;

    if (this.panes.indexOf(this._exitingPane) === -1) {
      this._exitingPane = null;
    }

    if (nextActiveKey !== currentActiveKey && currentKeyIsStillValid) {
      this._exitingPane = currentActiveKey;
    }
  },

  render() {
    let { className, children } = this.props;
    let Component = this.props.componentClass;

    let contentClass = prefix(this.props, 'content');

    return (
      <Component className={cn(contentClass, className)}>
        { children }
      </Component>
    );
  },

  handlePaneExited() {
    this._exitingPane = null;
    this.forceUpdate();
  },

  /**
   * This is unfortunately neccessary because the TabContent needs to know if
   * a TabPane is ever going to exit, since it may unmount and just leave the
   * TabContent to wait longingly forever for the handlePaneExited to be called.
   */
  registerPane(eventKey) {
    let panes = this.panes || (this.panes = []);

    invariant(panes.indexOf(eventKey) === -1,
      'You cannot have multiple TabPanes of with the same `eventKey` in the same ' +
      'TabContent component. Duplicate eventKey: ' + eventKey
    );

    panes.push(eventKey);

    return ()=> {
      panes.splice(panes.indexOf(eventKey), 1);
      if (eventKey === this.getActiveKey()) {
        this.getContext('$bs_tabcontainer').onSelect();
      }
    };
  },

  getActiveKey(context = this.context) {
    return this.getContext('$bs_tabcontainer', context).activeKey;
  },

  getContext(key, context = this.context) {
    return context[key] || {};
  }
});

export default setBsClass('tab', TabContent);
<commit_msg>fix tab bug<commit_after>import cn from 'classnames';
import invariant from 'invariant';
import React, { PropTypes } from 'react';
import elementType from 'react-prop-types/lib/elementType';

import { bsClass as setBsClass, prefix } from './utils/bootstrapUtils';

let animationPropType = PropTypes.oneOfType([
  PropTypes.bool,
  elementType
]);

let TabContent = React.createClass({

  propTypes: {

    /**
     * the Component used to render the TabContent
     */
    componentClass: elementType,

    /**
     * Sets a default animation strategy for all children TabPanes.
     * Use `false` to disable, `true` to enable the default "Fade"
     * animation or any `<Transition>` component.
     */
    animation: PropTypes.oneOfType([
      PropTypes.bool,
      elementType
    ]),
  },

  contextTypes: {
    $bs_tabcontainer: React.PropTypes.shape({
      activeKey: React.PropTypes.any,
      onSelect: PropTypes.func,
    })
  },

  childContextTypes: {
    $bs_tabcontent: PropTypes.shape({
      bsClass: PropTypes.string,
      animation: animationPropType,
      activeKey: PropTypes.any,
      onExited: PropTypes.func,
      register: PropTypes.func
    }),
  },

  getDefaultProps() {
    return {
      componentClass: 'div',
      animation: true
    };
  },

  getInitialState() {
    return {
      exitingPane: null
    };
  },

  getChildContext() {
    let exitingPane = this._exitingPane;

    return {
      $bs_tabcontent: {
        bsClass: this.props.bsClass,
        animation: this.props.animation,
        activeKey: exitingPane ? undefined : this.getActiveKey(),
        onExited: this.handlePaneExited,
        register: this.registerPane
      }
    };
  },

  componentWillMount() {
    this.panes = [];
  },

  /**
   * This belongs in `componentWillReceiveProps()` but
   * 0.14.x contains a bug where cwrp isn't called when only context changes.
   * fixed in master, not sure it will make it into any 0.14 release
   */
  componentWillUpdate(nextProps, _, nextContext) {
    let currentActiveKey = this.getActiveKey();
    let nextActiveKey = this.getActiveKey(nextContext);
    let currentKeyIsStillValid = this.panes.indexOf(currentActiveKey) !== -1;

    if (this.panes.indexOf(this._exitingPane) === -1) {
      this._exitingPane = null;
    }

    if (nextActiveKey !== currentActiveKey && currentKeyIsStillValid) {
      this._exitingPane = currentActiveKey;
    }
  },

  render() {
    let { className, children } = this.props;
    let Component = this.props.componentClass;

    let contentClass = prefix(this.props, 'content');

    return (
      <Component className={cn(contentClass, className)}>
        { children }
      </Component>
    );
  },

  handlePaneExited() {
    this._exitingPane = null;
    this.forceUpdate();
  },

  /**
   * This is unfortunately neccessary because the TabContent needs to know if
   * a TabPane is ever going to exit, since it may unmount and just leave the
   * TabContent to wait longingly forever for the handlePaneExited to be called.
   */
  registerPane(eventKey) {
    let panes = this.panes;

    invariant(panes.indexOf(eventKey) === -1,
      'You cannot have multiple TabPanes of with the same `eventKey` in the same ' +
      'TabContent component. Duplicate eventKey: ' + eventKey
    );

    panes.push(eventKey);

    return ()=> {
      panes.splice(panes.indexOf(eventKey), 1);
      if (eventKey === this.getActiveKey()) {
        this.getContext('$bs_tabcontainer').onSelect();
      }
    };
  },

  getActiveKey(context = this.context) {
    return this.getContext('$bs_tabcontainer', context).activeKey;
  },

  getContext(key, context = this.context) {
    return context[key] || {};
  }
});

export default setBsClass('tab', TabContent);
<|endoftext|>


<commit_before>var sd = (function () {
	var method = {
        year: function (year) {
			if (!year) { year = new Date() };
			if (year instanceof Date) { year = year.getFullYear() };
			var startDate = new Date(year, 0, 1, 0, 0, 0, 0);
			var endDate = new Date(year, 11 + 1, 0);
			loopDates(startDate, endDate);

        },
		month: function (year, month) {
			if (!year) { year = new Date() };
			if (year instanceof Date) {
				month = year.getMonth() + 1;
				year = year.getFullYear();
			};
			var startDate = new Date(year, month - 1, 1, 0, 0, 0, 0);
			var endDate = new Date(year, month, 0);
			loopDates(startDate, endDate);
        },
		calendarYear: function (year) {
			if (!year) { year = new Date() };
			if (year instanceof Date) { year = year.getFullYear() };
			var startDate = getMonday(new Date(year, 0, 1, 0, 0, 0, 0));
			var endDate = getSunday(new Date(year, 11 + 1, 0));
			loopDates(startDate, endDate);
        },
		calendarMonth: function (year, month) {
			if (!year) { year = new Date() };
			if (year instanceof Date) {
				month = year.getMonth() + 1;
				year = year.getFullYear();
			};
			var startDate = getMonday(new Date(year, month - 1, 1, 0, 0, 0, 0));
			var endDate = getSunday(new Date(year, month, 0));
			loopDates(startDate, endDate);
        },
		week: function (year, month, day) {
			if (!year) { year = new Date() };
			if (year instanceof Date) {
				day = year.getDate();
				month = year.getMonth() + 1;
				year = year.getFullYear();
			};
			var startDate = getMonday(new Date(year, month - 1, day));
			var endDate = getSunday(new Date(year, month - 1, day))
			loopDates(startDate, endDate);
        },
		weekByNumber: function (year, week) {
			var startDate = w2date(year, week, 0);
			var endDate = w2date(year, week, 6);
			loopDates(startDate, endDate);
        },
		day: function (year, month, day) {
			if (!year) { year = new Date() };
			if (year instanceof Date) {
				day = year.getDate();
				month = year.getMonth() + 1;
				year = year.getFullYear();
			};
			var startDate = new Date(year, month - 1, day, 0, 0, 0, 0)
			var endDate = startDate;
			loopDates(startDate, endDate);
        }
    }

    return method;

	//helpers
	function getMonday(d) {
		d = new Date(d);
		var day = d.getDay(),
			diff = d.getDate() - day + (day == 0 ? -6 : 1); // adjust when day is sunday
		return new Date(d.setDate(diff));
	}

	function getSunday(d) {
		d = new Date(d);
		var day = d.getDay(),
			diff = d.getDate() - day + (day == 0 ? 0 : 7); // dont adjust when day is sunday
		return new Date(d.setDate(diff));
	}

	function easter(Y) {
		var C = Math.floor(Y / 100);
		var N = Y - 19 * Math.floor(Y / 19);
		var K = Math.floor((C - 17) / 25);
		var I = C - Math.floor(C / 4) - Math.floor((C - K) / 3) + 19 * N + 15;
		I = I - 30 * Math.floor((I / 30));
		I = I - Math.floor(I / 28) * (1 - Math.floor(I / 28) * Math.floor(29 / (I + 1)) * Math.floor((21 - N) / 11));
		var J = Y + Math.floor(Y / 4) + I + 2 - C + Math.floor(C / 4);
		J = J - 7 * Math.floor(J / 7);
		var L = I - J;
		var M = 3 + Math.floor((L + 40) / 44);
		var D = L + 28 - 31 * Math.floor(M / 4);
		return new Date(Y, M - 1, D)
	}

	function w2date(year, wn, dayNb) {
		var j10 = new Date(year, 0, 10, 12, 0, 0),
			j4 = new Date(year, 0, 4, 12, 0, 0),
			mon1 = j4.getTime() - j10.getDay() * 86400000;
		return new Date(mon1 + ((wn - 1) * 7 + dayNb) * 86400000);
	};

	function loopDates (startDate, endDate) {
		for (var d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) {
    	console.log(d)
		}
	};

} ());
<commit_msg>refresh2<commit_after>var sd = (function () {
	var method = {
        year: function (year) {
			if (!year) { year = new Date() };
			if (year instanceof Date) { year = year.getFullYear() };
			var startDate = new Date(year, 0, 1, 0, 0, 0, 0);
			var endDate = new Date(year, 11 + 1, 0);
			loopDates(startDate, endDate);

        },
		month: function (year, month) {
			if (!year) { year = new Date() };
			if (year instanceof Date) {
				month = year.getMonth() + 1;
				year = year.getFullYear();
			};
			var startDate = new Date(year, month - 1, 1, 0, 0, 0, 0);
			var endDate = new Date(year, month, 0);
			loopDates(startDate, endDate);
        },
		calendarYear: function (year) {
			if (!year) { year = new Date() };
			if (year instanceof Date) { year = year.getFullYear() };
			var startDate = getMonday(new Date(year, 0, 1, 0, 0, 0, 0));
			var endDate = getSunday(new Date(year, 11 + 1, 0));
			loopDates(startDate, endDate);
        },
		calendarMonth: function (year, month) {
			if (!year) { year = new Date() };
			if (year instanceof Date) {
				month = year.getMonth() + 1;
				year = year.getFullYear();
			};
			var startDate = getMonday(new Date(year, month - 1, 1, 0, 0, 0, 0));
			var endDate = getSunday(new Date(year, month, 0));
			loopDates(startDate, endDate);
        },
		week: function (year, month, day) {
			if (!year) { year = new Date() };
			if (year instanceof Date) {
				day = year.getDate();
				month = year.getMonth() + 1;
				year = year.getFullYear();
			};
			var startDate = getMonday(new Date(year, month - 1, day));
			var endDate = getSunday(new Date(year, month - 1, day))
			loopDates(startDate, endDate);
        },
		weekByNumber: function (year, week) {
			var startDate = w2date(year, week, 0);
			var endDate = w2date(year, week, 6);
			loopDates(startDate, endDate);
        },
		day: function (year, month, day) {
			if (!year) { year = new Date() };
			if (year instanceof Date) {
				day = year.getDate();
				month = year.getMonth() + 1;
				year = year.getFullYear();
			};
			var startDate = new Date(year, month - 1, day, 0, 0, 0, 0)
			var endDate = startDate;
			loopDates(startDate, endDate);
        }
    }

    return method;

	//helpers
	function getMonday(d) {
		d = new Date(d);
		var day = d.getDay(),
			diff = d.getDate() - day + (day == 0 ? -6 : 1); // adjust when day is sunday
		return new Date(d.setDate(diff));
	}

	function getSunday(d) {
		d = new Date(d);
		var day = d.getDay(),
			diff = d.getDate() - day + (day == 0 ? 0 : 7); // dont adjust when day is sunday
		return new Date(d.setDate(diff));
	}

	function easter(Y) {
		var C = Math.floor(Y / 100);
		var N = Y - 19 * Math.floor(Y / 19);
		var K = Math.floor((C - 17) / 25);
		var I = C - Math.floor(C / 4) - Math.floor((C - K) / 3) + 19 * N + 15;
		I = I - 30 * Math.floor((I / 30));
		I = I - Math.floor(I / 28) * (1 - Math.floor(I / 28) * Math.floor(29 / (I + 1)) * Math.floor((21 - N) / 11));
		var J = Y + Math.floor(Y / 4) + I + 2 - C + Math.floor(C / 4);
		J = J - 7 * Math.floor(J / 7);
		var L = I - J;
		var M = 3 + Math.floor((L + 40) / 44);
		var D = L + 28 - 31 * Math.floor(M / 4);
		return new Date(Y, M - 1, D)
	}

	function w2date(year, wn, dayNb) {
		var j10 = new Date(year, 0, 10, 12, 0, 0),
			j4 = new Date(year, 0, 4, 12, 0, 0),
			mon1 = j4.getTime() - j10.getDay() * 86400000;
		return new Date(mon1 + ((wn - 1) * 7 + dayNb) * 86400000);
	};

	function loopDates (startDate, endDate) {
		for (var d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) {
    	console.log(d)
		}
	};

} ());<|endoftext|>


<commit_before>/**
 * SVGInjector v1.1.0 - Fast, caching, dynamic inline SVG DOM injection library
 * https://github.com/iconic/SVGInjector
 *
 * Copyright (c) 2014 Waybury <hello@waybury.com>
 * @license MIT
 */

(function (window, document) {

  'use strict';

  // Environment
  var isLocal = window.location.protocol === 'file:';
  var hasSvgSupport = document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1');

  function uniqueClasses(list) {
    list = list.split(' ');

    var hash = {};
    var i = list.length;
    var out = [];

    while (i--) {
      if (!hash.hasOwnProperty(list[i])) {
        hash[list[i]] = 1;
        out.unshift(list[i]);
      }
    }

    return out.join(' ');
  }

  /**
   * cache (or polyfill for <= IE8) Array.forEach()
   * source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
   */
  var forEach = Array.prototype.forEach || function (fn, scope) {
    if (this === void 0 || this === null || typeof fn !== 'function') {
      throw new TypeError();
    }

    /* jshint bitwise: false */
    var i, len = this.length >>> 0;
    /* jshint bitwise: true */

    for (i = 0; i < len; ++i) {
      if (i in this) {
        fn.call(scope, this[i], i, this);
      }
    }
  };

  // SVG Cache
  var svgCache = {};

  var injectCount = 0;
  var injectedElements = [];

  // Request Queue
  var requestQueue = [];

  // Script running status
  var ranScripts = {};

  var cloneSvg = function (sourceSvg) {
    return sourceSvg.cloneNode(true);
  };

  var queueRequest = function (url, callback) {
    requestQueue[url] = requestQueue[url] || [];
    requestQueue[url].push(callback);
  };

  var processRequestQueue = function (url) {
    for (var i = 0, len = requestQueue[url].length; i < len; i++) {
      // Make these calls async so we avoid blocking the page/renderer
      /* jshint loopfunc: true */
      (function (index) {
        setTimeout(function () {
          requestQueue[url][index](cloneSvg(svgCache[url]));
        }, 0);
      })(i);
      /* jshint loopfunc: false */
    }
  };

  var loadSvg = function (url, callback) {
    if (svgCache[url] !== undefined) {
      if (svgCache[url] instanceof SVGSVGElement) {
        // We already have it in cache, so use it
        callback(cloneSvg(svgCache[url]));
      }
      else {
        // We don't have it in cache yet, but we are loading it, so queue this request
        queueRequest(url, callback);
      }
    }
    else {

      if (!window.XMLHttpRequest) {
        callback('Browser does not support XMLHttpRequest');
        return false;
      }

      // Seed the cache to indicate we are loading this URL already
      svgCache[url] = {};
      queueRequest(url, callback);

      var httpRequest = new XMLHttpRequest();

      httpRequest.onreadystatechange = function () {
        // readyState 4 = complete
        if (httpRequest.readyState === 4) {

          // Handle status
          if (httpRequest.status === 404 || httpRequest.responseXML === null) {
            callback('Unable to load SVG file: ' + url);

            if (isLocal) callback('Note: SVG injection ajax calls do not work locally without adjusting security setting in your browser. Or consider using a local webserver.');

            callback();
            return false;
          }

          // 200 success from server, or 0 when using file:// protocol locally
          if (httpRequest.status === 200 || (isLocal && httpRequest.status === 0)) {

            /* globals Document */
            if (httpRequest.responseXML instanceof Document) {
              // Cache it
              svgCache[url] = httpRequest.responseXML.documentElement;
            }
            /* globals -Document */

            // IE9 doesn't create a responseXML Document object from loaded SVG,
            // and throws a "DOM Exception: HIERARCHY_REQUEST_ERR (3)" error when injected.
            //
            // So, we'll just create our own manually via the DOMParser using
            // the the raw XML responseText.
            //
            // :NOTE: IE8 and older doesn't have DOMParser, but they can't do SVG either, so...
            else if (DOMParser && (DOMParser instanceof Function)) {
              var xmlDoc;
              try {
                var parser = new DOMParser();
                xmlDoc = parser.parseFromString(httpRequest.responseText, 'text/xml');
              }
              catch (e) {
                xmlDoc = undefined;
              }

              if (!xmlDoc || xmlDoc.getElementsByTagName('parsererror').length) {
                callback('Unable to parse SVG file: ' + url);
                return false;
              }
              else {
                // Cache it
                svgCache[url] = xmlDoc.documentElement;
              }
            }

            // We've loaded a new asset, so process any requests waiting for it
            processRequestQueue(url);
          }
          else {
            callback('There was a problem injecting the SVG: ' + httpRequest.status + ' ' + httpRequest.statusText);
            return false;
          }
        }
      };

      httpRequest.open('GET', url);

      // Treat and parse the response as XML, even if the
      // server sends us a different mimetype
      if (httpRequest.overrideMimeType) httpRequest.overrideMimeType('text/xml');

      httpRequest.send();
    }
  };

  // Inject a single element
  var injectElement = function (el, evalScripts, pngFallback, callback) {

    // Grab the src or data-src attribute
    var imgUrl = el.getAttribute('data-src') || el.getAttribute('src');

    // We can only inject SVG
    if (!(/svg$/i).test(imgUrl)) {
      callback('Attempted to inject a file with a non-svg extension: ' + imgUrl);
      return;
    }

    // If we don't have SVG support try to fall back to a png,
    // either defined per-element via data-fallback or data-png,
    // or globally via the pngFallback directory setting
    if (!hasSvgSupport) {
      var perElementFallback = el.getAttribute('data-fallback') || el.getAttribute('data-png');

      // Per-element specific PNG fallback defined, so use that
      if (perElementFallback) {
        el.setAttribute('src', perElementFallback);
        callback(null);
      }
      // Global PNG fallback directoriy defined, use the same-named PNG
      else if (pngFallback) {
        el.setAttribute('src', pngFallback + '/' + imgUrl.split('/').pop().replace('.svg', '.png'));
        callback(null);
      }
      // um...
      else {
        callback('This browser does not support SVG and no PNG fallback was defined.');
      }

      return;
    }

    // Make sure we aren't already in the process of injecting this element to
    // avoid a race condition if multiple injections for the same element are run.
    // :NOTE: Using indexOf() only _after_ we check for SVG support and bail,
    // so no need for IE8 indexOf() polyfill
    if (injectedElements.indexOf(el) !== -1) {
      return;
    }

    // Remember the request to inject this element, in case other injection
    // calls are also trying to replace this element before we finish
    injectedElements.push(el);

    // Try to avoid loading the orginal image src if possible.
    el.setAttribute('src', '');

    // Load it up
    loadSvg(imgUrl, function (svg) {

      if (typeof svg === 'undefined' || typeof svg === 'string') {
        callback(svg);
        return false;
      }

      var imgId = el.getAttribute('id');
      if (imgId) {
        svg.setAttribute('id', imgId);
      }

      var imgTitle = el.getAttribute('title');
      if (imgTitle) {
        svg.setAttribute('title', imgTitle);
      }

      // Concat the SVG classes + 'injected-svg' + the img classes
      var classMerge = [].concat(svg.getAttribute('class') || [], 'injected-svg', el.getAttribute('class') || []).join(' ');
      svg.setAttribute('class', uniqueClasses(classMerge));

      var imgStyle = el.getAttribute('style');
      if (imgStyle) {
        svg.setAttribute('style', imgStyle);
      }

      // Copy all the data elements to the svg
      var imgData = [].filter.call(el.attributes, function (at) {
        return (/^data-\w[\w\-]*$/).test(at.name);
      });
      forEach.call(imgData, function (dataAttr) {
        if (dataAttr.name && dataAttr.value) {
          svg.setAttribute(dataAttr.name, dataAttr.value);
        }
      });

      // Make sure any internally referenced clipPath ids and their
      // clip-path references are unique.
      //
      // This addresses the issue of having multiple instances of the
      // same SVG on a page and only the first clipPath id is referenced.
      //
      // Browsers often shortcut the SVG Spec and don't use clipPaths
      // contained in parent elements that are hidden, so if you hide the first
      // SVG instance on the page, then all other instances lose their clipping.
      // Reference: https://bugzilla.mozilla.org/show_bug.cgi?id=376027
      var clipPaths = svg.querySelectorAll('defs clipPath[id]');
      var newClipPathName;
      for (var i = 0, clipPathsLen = clipPaths.length; i < clipPathsLen; i++) {
        newClipPathName = clipPaths[i].id + '-' + injectCount;
        // :NOTE: using a substring match attr selector here to deal with IE "adding extra quotes in url() attrs"
        var usingClipPath = svg.querySelectorAll('[clip-path*="' + clipPaths[i].id + '"]');
        for (var j = 0, usingClipPathLen = usingClipPath.length; j < usingClipPathLen; j++) {
          usingClipPath[j].setAttribute('clip-path', 'url(#' + newClipPathName + ')');
        }
        clipPaths[i].id = newClipPathName;
      }

      // Remove any unwanted/invalid namespaces that might have been added by SVG editing tools
      svg.removeAttribute('xmlns:a');

      // Post page load injected SVGs don't automatically have their script
      // elements run, so we'll need to make that happen, if requested

      // Find then prune the scripts
      var scripts = svg.querySelectorAll('script');
      var scriptsToEval = [];
      var script, scriptType;

      for (var k = 0, scriptsLen = scripts.length; k < scriptsLen; k++) {
        scriptType = scripts[k].getAttribute('type');

        // Only process javascript types.
        // SVG defaults to 'application/ecmascript' for unset types
        if (!scriptType || scriptType === 'application/ecmascript' || scriptType === 'application/javascript') {

          // innerText for IE, textContent for other browsers
          script = scripts[k].innerText || scripts[k].textContent;

          // Stash
          scriptsToEval.push(script);

          // Tidy up and remove the script element since we don't need it anymore
          svg.removeChild(scripts[k]);
        }
      }

      // Run/Eval the scripts if needed
      if (scriptsToEval.length > 0 && (evalScripts === 'always' || (evalScripts === 'once' && !ranScripts[imgUrl]))) {
        for (var l = 0, scriptsToEvalLen = scriptsToEval.length; l < scriptsToEvalLen; l++) {

          // :NOTE: Yup, this is a form of eval, but it is being used to eval code
          // the caller has explictely asked to be loaded, and the code is in a caller
          // defined SVG file... not raw user input.
          //
          // Also, the code is evaluated in a closure and not in the global scope.
          // If you need to put something in global scope, use 'window'
          new Function(scriptsToEval[l])(window); // jshint ignore:line
        }

        // Remember we already ran scripts for this svg
        ranScripts[imgUrl] = true;
      }

      // Replace the image with the svg
      el.parentNode.replaceChild(svg, el);

      // Now that we no longer need it, drop references
      // to the original element so it can be GC'd
      delete injectedElements[injectedElements.indexOf(el)];
      el = null;

      // Increment the injected count
      injectCount++;

      callback(svg);
    });
  };

  /**
   * SVGInjector
   *
   * Replace the given elements with their full inline SVG DOM elements.
   *
   * :NOTE: We are using get/setAttribute with SVG because the SVG DOM spec differs from HTML DOM and
   * can return other unexpected object types when trying to directly access svg properties.
   * ex: "className" returns a SVGAnimatedString with the class value found in the "baseVal" property,
   * instead of simple string like with HTML Elements.
   *
   * @param {mixes} Array of or single DOM element
   * @param {object} options
   * @param {function} callback
   * @return {object} Instance of SVGInjector
   */
  var SVGInjector = function (elements, options, done) {

    // Options & defaults
    options = options || {};

    // Should we run the scripts blocks found in the SVG
    // 'always' - Run them every time
    // 'once' - Only run scripts once for each SVG
    // [false|'never'] - Ignore scripts
    var evalScripts = options.evalScripts || 'always';

    // Location of fallback pngs, if desired
    var pngFallback = options.pngFallback || false;

    // Callback to run during each SVG injection, returning the SVG injected
    var eachCallback = options.each;

    // Do the injection...
    if (elements.length !== undefined) {
      var elementsLoaded = 0;
      forEach.call(elements, function (element) {
        injectElement(element, evalScripts, pngFallback, function (svg) {
          if (eachCallback && typeof eachCallback === 'function') eachCallback(svg);
          if (done && elements.length === ++elementsLoaded) done(elementsLoaded);
        });
      });
    }
    else {
      if (elements) {
        injectElement(elements, evalScripts, pngFallback, function (svg) {
          if (eachCallback && typeof eachCallback === 'function') eachCallback(svg);
          if (done) done(1);
        });
      }
      else {
        if (done) done(0);
      }
    }
  };

  /* global module, exports: true, define */
  // Node.js or CommonJS
  if (typeof module === 'object' && typeof module.exports === 'object') {
    module.exports = exports = SVGInjector;
  }
  // AMD support
  else if (typeof define === 'function' && define.amd) {
    define(function () {
      return SVGInjector;
    });
  }
  // Otherwise, attach to window as global
  else if (typeof window === 'object') {
    window.SVGInjector = SVGInjector;
  }
  /* global -module, -exports, -define */

}(window, document));
<commit_msg>Unlink elements var to aid GC and avoid detacted DOM elements<commit_after>/**
 * SVGInjector v1.1.0 - Fast, caching, dynamic inline SVG DOM injection library
 * https://github.com/iconic/SVGInjector
 *
 * Copyright (c) 2014 Waybury <hello@waybury.com>
 * @license MIT
 */

(function (window, document) {

  'use strict';

  // Environment
  var isLocal = window.location.protocol === 'file:';
  var hasSvgSupport = document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1');

  function uniqueClasses(list) {
    list = list.split(' ');

    var hash = {};
    var i = list.length;
    var out = [];

    while (i--) {
      if (!hash.hasOwnProperty(list[i])) {
        hash[list[i]] = 1;
        out.unshift(list[i]);
      }
    }

    return out.join(' ');
  }

  /**
   * cache (or polyfill for <= IE8) Array.forEach()
   * source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
   */
  var forEach = Array.prototype.forEach || function (fn, scope) {
    if (this === void 0 || this === null || typeof fn !== 'function') {
      throw new TypeError();
    }

    /* jshint bitwise: false */
    var i, len = this.length >>> 0;
    /* jshint bitwise: true */

    for (i = 0; i < len; ++i) {
      if (i in this) {
        fn.call(scope, this[i], i, this);
      }
    }
  };

  // SVG Cache
  var svgCache = {};

  var injectCount = 0;
  var injectedElements = [];

  // Request Queue
  var requestQueue = [];

  // Script running status
  var ranScripts = {};

  var cloneSvg = function (sourceSvg) {
    return sourceSvg.cloneNode(true);
  };

  var queueRequest = function (url, callback) {
    requestQueue[url] = requestQueue[url] || [];
    requestQueue[url].push(callback);
  };

  var processRequestQueue = function (url) {
    for (var i = 0, len = requestQueue[url].length; i < len; i++) {
      // Make these calls async so we avoid blocking the page/renderer
      /* jshint loopfunc: true */
      (function (index) {
        setTimeout(function () {
          requestQueue[url][index](cloneSvg(svgCache[url]));
        }, 0);
      })(i);
      /* jshint loopfunc: false */
    }
  };

  var loadSvg = function (url, callback) {
    if (svgCache[url] !== undefined) {
      if (svgCache[url] instanceof SVGSVGElement) {
        // We already have it in cache, so use it
        callback(cloneSvg(svgCache[url]));
      }
      else {
        // We don't have it in cache yet, but we are loading it, so queue this request
        queueRequest(url, callback);
      }
    }
    else {

      if (!window.XMLHttpRequest) {
        callback('Browser does not support XMLHttpRequest');
        return false;
      }

      // Seed the cache to indicate we are loading this URL already
      svgCache[url] = {};
      queueRequest(url, callback);

      var httpRequest = new XMLHttpRequest();

      httpRequest.onreadystatechange = function () {
        // readyState 4 = complete
        if (httpRequest.readyState === 4) {

          // Handle status
          if (httpRequest.status === 404 || httpRequest.responseXML === null) {
            callback('Unable to load SVG file: ' + url);

            if (isLocal) callback('Note: SVG injection ajax calls do not work locally without adjusting security setting in your browser. Or consider using a local webserver.');

            callback();
            return false;
          }

          // 200 success from server, or 0 when using file:// protocol locally
          if (httpRequest.status === 200 || (isLocal && httpRequest.status === 0)) {

            /* globals Document */
            if (httpRequest.responseXML instanceof Document) {
              // Cache it
              svgCache[url] = httpRequest.responseXML.documentElement;
            }
            /* globals -Document */

            // IE9 doesn't create a responseXML Document object from loaded SVG,
            // and throws a "DOM Exception: HIERARCHY_REQUEST_ERR (3)" error when injected.
            //
            // So, we'll just create our own manually via the DOMParser using
            // the the raw XML responseText.
            //
            // :NOTE: IE8 and older doesn't have DOMParser, but they can't do SVG either, so...
            else if (DOMParser && (DOMParser instanceof Function)) {
              var xmlDoc;
              try {
                var parser = new DOMParser();
                xmlDoc = parser.parseFromString(httpRequest.responseText, 'text/xml');
              }
              catch (e) {
                xmlDoc = undefined;
              }

              if (!xmlDoc || xmlDoc.getElementsByTagName('parsererror').length) {
                callback('Unable to parse SVG file: ' + url);
                return false;
              }
              else {
                // Cache it
                svgCache[url] = xmlDoc.documentElement;
              }
            }

            // We've loaded a new asset, so process any requests waiting for it
            processRequestQueue(url);
          }
          else {
            callback('There was a problem injecting the SVG: ' + httpRequest.status + ' ' + httpRequest.statusText);
            return false;
          }
        }
      };

      httpRequest.open('GET', url);

      // Treat and parse the response as XML, even if the
      // server sends us a different mimetype
      if (httpRequest.overrideMimeType) httpRequest.overrideMimeType('text/xml');

      httpRequest.send();
    }
  };

  // Inject a single element
  var injectElement = function (el, evalScripts, pngFallback, callback) {

    // Grab the src or data-src attribute
    var imgUrl = el.getAttribute('data-src') || el.getAttribute('src');

    // We can only inject SVG
    if (!(/svg$/i).test(imgUrl)) {
      callback('Attempted to inject a file with a non-svg extension: ' + imgUrl);
      return;
    }

    // If we don't have SVG support try to fall back to a png,
    // either defined per-element via data-fallback or data-png,
    // or globally via the pngFallback directory setting
    if (!hasSvgSupport) {
      var perElementFallback = el.getAttribute('data-fallback') || el.getAttribute('data-png');

      // Per-element specific PNG fallback defined, so use that
      if (perElementFallback) {
        el.setAttribute('src', perElementFallback);
        callback(null);
      }
      // Global PNG fallback directoriy defined, use the same-named PNG
      else if (pngFallback) {
        el.setAttribute('src', pngFallback + '/' + imgUrl.split('/').pop().replace('.svg', '.png'));
        callback(null);
      }
      // um...
      else {
        callback('This browser does not support SVG and no PNG fallback was defined.');
      }

      return;
    }

    // Make sure we aren't already in the process of injecting this element to
    // avoid a race condition if multiple injections for the same element are run.
    // :NOTE: Using indexOf() only _after_ we check for SVG support and bail,
    // so no need for IE8 indexOf() polyfill
    if (injectedElements.indexOf(el) !== -1) {
      return;
    }

    // Remember the request to inject this element, in case other injection
    // calls are also trying to replace this element before we finish
    injectedElements.push(el);

    // Try to avoid loading the orginal image src if possible.
    el.setAttribute('src', '');

    // Load it up
    loadSvg(imgUrl, function (svg) {

      if (typeof svg === 'undefined' || typeof svg === 'string') {
        callback(svg);
        return false;
      }

      var imgId = el.getAttribute('id');
      if (imgId) {
        svg.setAttribute('id', imgId);
      }

      var imgTitle = el.getAttribute('title');
      if (imgTitle) {
        svg.setAttribute('title', imgTitle);
      }

      // Concat the SVG classes + 'injected-svg' + the img classes
      var classMerge = [].concat(svg.getAttribute('class') || [], 'injected-svg', el.getAttribute('class') || []).join(' ');
      svg.setAttribute('class', uniqueClasses(classMerge));

      var imgStyle = el.getAttribute('style');
      if (imgStyle) {
        svg.setAttribute('style', imgStyle);
      }

      // Copy all the data elements to the svg
      var imgData = [].filter.call(el.attributes, function (at) {
        return (/^data-\w[\w\-]*$/).test(at.name);
      });
      forEach.call(imgData, function (dataAttr) {
        if (dataAttr.name && dataAttr.value) {
          svg.setAttribute(dataAttr.name, dataAttr.value);
        }
      });

      // Make sure any internally referenced clipPath ids and their
      // clip-path references are unique.
      //
      // This addresses the issue of having multiple instances of the
      // same SVG on a page and only the first clipPath id is referenced.
      //
      // Browsers often shortcut the SVG Spec and don't use clipPaths
      // contained in parent elements that are hidden, so if you hide the first
      // SVG instance on the page, then all other instances lose their clipping.
      // Reference: https://bugzilla.mozilla.org/show_bug.cgi?id=376027
      var clipPaths = svg.querySelectorAll('defs clipPath[id]');
      var newClipPathName;
      for (var i = 0, clipPathsLen = clipPaths.length; i < clipPathsLen; i++) {
        newClipPathName = clipPaths[i].id + '-' + injectCount;
        // :NOTE: using a substring match attr selector here to deal with IE "adding extra quotes in url() attrs"
        var usingClipPath = svg.querySelectorAll('[clip-path*="' + clipPaths[i].id + '"]');
        for (var j = 0, usingClipPathLen = usingClipPath.length; j < usingClipPathLen; j++) {
          usingClipPath[j].setAttribute('clip-path', 'url(#' + newClipPathName + ')');
        }
        clipPaths[i].id = newClipPathName;
      }

      // Remove any unwanted/invalid namespaces that might have been added by SVG editing tools
      svg.removeAttribute('xmlns:a');

      // Post page load injected SVGs don't automatically have their script
      // elements run, so we'll need to make that happen, if requested

      // Find then prune the scripts
      var scripts = svg.querySelectorAll('script');
      var scriptsToEval = [];
      var script, scriptType;

      for (var k = 0, scriptsLen = scripts.length; k < scriptsLen; k++) {
        scriptType = scripts[k].getAttribute('type');

        // Only process javascript types.
        // SVG defaults to 'application/ecmascript' for unset types
        if (!scriptType || scriptType === 'application/ecmascript' || scriptType === 'application/javascript') {

          // innerText for IE, textContent for other browsers
          script = scripts[k].innerText || scripts[k].textContent;

          // Stash
          scriptsToEval.push(script);

          // Tidy up and remove the script element since we don't need it anymore
          svg.removeChild(scripts[k]);
        }
      }

      // Run/Eval the scripts if needed
      if (scriptsToEval.length > 0 && (evalScripts === 'always' || (evalScripts === 'once' && !ranScripts[imgUrl]))) {
        for (var l = 0, scriptsToEvalLen = scriptsToEval.length; l < scriptsToEvalLen; l++) {

          // :NOTE: Yup, this is a form of eval, but it is being used to eval code
          // the caller has explictely asked to be loaded, and the code is in a caller
          // defined SVG file... not raw user input.
          //
          // Also, the code is evaluated in a closure and not in the global scope.
          // If you need to put something in global scope, use 'window'
          new Function(scriptsToEval[l])(window); // jshint ignore:line
        }

        // Remember we already ran scripts for this svg
        ranScripts[imgUrl] = true;
      }

      // Replace the image with the svg
      el.parentNode.replaceChild(svg, el);

      // Now that we no longer need it, drop references
      // to the original element so it can be GC'd
      delete injectedElements[injectedElements.indexOf(el)];
      el = null;

      // Increment the injected count
      injectCount++;

      callback(svg);
    });
  };

  /**
   * SVGInjector
   *
   * Replace the given elements with their full inline SVG DOM elements.
   *
   * :NOTE: We are using get/setAttribute with SVG because the SVG DOM spec differs from HTML DOM and
   * can return other unexpected object types when trying to directly access svg properties.
   * ex: "className" returns a SVGAnimatedString with the class value found in the "baseVal" property,
   * instead of simple string like with HTML Elements.
   *
   * @param {mixes} Array of or single DOM element
   * @param {object} options
   * @param {function} callback
   * @return {object} Instance of SVGInjector
   */
  var SVGInjector = function (elements, options, done) {

    // Options & defaults
    options = options || {};

    // Should we run the scripts blocks found in the SVG
    // 'always' - Run them every time
    // 'once' - Only run scripts once for each SVG
    // [false|'never'] - Ignore scripts
    var evalScripts = options.evalScripts || 'always';

    // Location of fallback pngs, if desired
    var pngFallback = options.pngFallback || false;

    // Callback to run during each SVG injection, returning the SVG injected
    var eachCallback = options.each;

    // Do the injection...
    if (elements.length !== undefined) {
      var elementsLoaded = 0;
      forEach.call(elements, function (element) {
        injectElement(element, evalScripts, pngFallback, function (svg) {
          if (eachCallback && typeof eachCallback === 'function') eachCallback(svg);
          if (done && elements.length === ++elementsLoaded) done(elementsLoaded);
        });
      });
    }
    else {
      if (elements) {
        injectElement(elements, evalScripts, pngFallback, function (svg) {
          if (eachCallback && typeof eachCallback === 'function') eachCallback(svg);
          if (done) done(1);
          elements = null;
        });
      }
      else {
        if (done) done(0);
      }
    }
  };

  /* global module, exports: true, define */
  // Node.js or CommonJS
  if (typeof module === 'object' && typeof module.exports === 'object') {
    module.exports = exports = SVGInjector;
  }
  // AMD support
  else if (typeof define === 'function' && define.amd) {
    define(function () {
      return SVGInjector;
    });
  }
  // Otherwise, attach to window as global
  else if (typeof window === 'object') {
    window.SVGInjector = SVGInjector;
  }
  /* global -module, -exports, -define */

}(window, document));
<|endoftext|>


<commit_before>/**
 * @ngdoc directive
 * @name aaSelect2
 *
 * @description
 * Description place holder.
 **/

angular
  .module('aa.select2', [])
  .directive('aaSelect2', ['$q', function ($q) {
    'use strict';
    return {
      require: 'ngModel',
      template: '<input type="text" />',
      replace: true,
      link: function (scope, element, attrs, ngModel) {

        //util
        //assumes object is defined
        function isEmptyObject(obj) {
          if (!Object.keys) {  //<=IE 8
            return JSON.stringify(obj) === "{}";
          }

          return Object.keys(obj).length === 0;
        }

        //native select2 options directly from the user. always takes precedence
        //copy the object before we muck with it in case multiple select2s are sharing settings
        var settings = angular.copy(scope.$eval(attrs.aaSelect2));

        if (!angular.isObject(settings) || isEmptyObject(settings)) {
          throw 'aa-select2 options must be specified. Ex: <div aa-select2="*options here*"...\r\n';
        }

        //possible select2 options derived from user selections on settings
        var derivedOpts = {},

        //directive settings (aka nice wrapper for select2)
          inAjaxMode = settings ? angular.isFunction(settings.options) : false,
          inLocalArrayMode = settings ? angular.isArray(settings.options) : false,
          inIdMode = settings && settings.mode ? settings.mode.indexOf('id') !== -1 : false,
          inObjectMode = settings && settings.mode ? settings.mode.indexOf('object') !== -1 : false,
          inTagsMode = settings && settings.mode ? settings.mode.indexOf('tags') !== -1 : false,
          inThisMode = settings && settings.id === "@this" && settings.text === "@this";

        //need a placeholder for allow clear to work
        //fix bug?/weird api odditiy
        if (settings.select2 && settings.select2.allowClear) {
          derivedOpts.placeholder = "Select...";
        }

        if (attrs.placeholder) {
          derivedOpts.placeholder = attrs.placeholder;
        }

        //configure select2's options per passed settings
        if (settings) {

          if (inThisMode) {
            settings.id = 'id';
            settings.text = 'text';
          } else {
            settings.id = settings.id || 'id';
            settings.text = settings.text || 'text';
          }

          //have 'options' client side in an array
          if (inLocalArrayMode) {
            derivedOpts.data = derivedOpts.data || {};
            derivedOpts.data.text = settings.text;

            if (inThisMode) {
              var newData = [];
              angular.forEach(settings.options, function (obj) {
                newData.push({id: obj, text: obj});
              });
              derivedOpts.data.results = newData;
            } else {
              derivedOpts.data.results = settings.options;
            }
          }

          //AJAX MODE
          //run a query to get options (search)
          if (inAjaxMode) {
            derivedOpts.query = function (query) {
              // TODO: Ought to handle the failure case, instead of spinning forever
              var queryResult = settings.options(query.term);
              // Assume if it's not a promise and is an array, it's data
              if (!queryResult.then && !!queryResult.length) {
                query.callback({
                  results: queryResult,
                  text: settings.text
                });
              } else {
                queryResult.then(function (data) {
                  if (inThisMode) {
                    var newData = [];
                    angular.forEach(data, function (str) {
                      newData.push({id: str, text: str});
                    });
                    data = newData;
                  }
                  query.callback({
                    results: data,
                    text: settings.text
                  });
                });
              }
            };

            if (inIdMode) {
              derivedOpts.initSelection = function (e, callback) {

                if (!ngModel.$modelValue) {
                  return;
                }

                if (inThisMode && inTagsMode) {
                  var newData = [];
                  angular.forEach(ngModel.$modelValue, function (str) {
                    newData.push({id: str, text: str});
                  });
                  callback(newData);
                  return;

                }

                if (inThisMode) {
                  callback({id: ngModel.$modelValue, text: ngModel.$modelValue});
                  return;
                }

                //allow for multiple lookups in tags mode (or just one in other modes)
                var modelValueIsArray = angular.isArray(ngModel.$modelValue),
                  lookups = [];

                if (modelValueIsArray) {
                  angular.forEach(ngModel.$modelValue, function (val) {
                    lookups.push(settings.textLookup(val));
                  });
                } else {
                  lookups.push(settings.textLookup(ngModel.$modelValue));
                }

                //resolves promises and resolved values alike
                $q.all(lookups)
                  .then(function (results) {
                    function resultMapper(data) {
                      var result;
                      if (angular.isUndefined(data.data)) {
                        result = data;
                      } else {
                        result = data.data;
                      }

                      if (!angular.isObject(result)) {
                        //passed back just the text. resolve:
                        var newResult = {};
                        newResult[settings.id] = ngModel.$modelValue;
                        newResult[settings.text] = result;
                        result = newResult;
                      }
                      return result;
                    }

                    if (modelValueIsArray) {
                      var mappedResults = [];

                      angular.forEach(results, function (result) {
                        mappedResults.push(resultMapper(result));
                      });

                      callback(mappedResults);
                    } else {
                      callback(resultMapper(results[0]));
                    }

                  });
              };
            }
          }

          derivedOpts.id = settings.id;

          derivedOpts.formatSelection = function (obj) {
            return obj[settings.text];
          };
          derivedOpts.formatResult = function (obj) {
            return obj[settings.text];
          };

          if (inTagsMode) {
            derivedOpts.tags = ngModel.$modelValue || [];
          }

        }

        var staticOpts = {
          width: 'resolve'
        };

        //order of prescedence for passing into select2 native api:
        //static opts loses first
        //then derivedOpts (the facade for select2 API that was created above aka what makes this plugin easy)
        //finally any explicit user opts passed into settings as 'select2' will always win
        var opts = angular.extend(staticOpts, derivedOpts, settings.select2);

        //setup select2 with options
        element.select2(opts);

        //programmatic changes to the model
        ngModel.$render = function () {

          if (!ngModel.$modelValue) {
            element.select2('val', "");
            return;
          }

          if (inIdMode) {
            element.select2('val', ngModel.$modelValue);
          } else if (inObjectMode) {
            element.select2('data', ngModel.$modelValue);
          }
        };

        //when select2 changes
        element.bind("change", function () {
          scope.$apply(function () {
            var select2Data = element.select2('data');

            var ngValue = null;

            if (!select2Data) {
              ngValue = null;
            } else if (inObjectMode) {
              ngValue = select2Data;
            } else if (inIdMode) {

              if (angular.isArray(select2Data)) {

                ngValue = [];
                angular.forEach(select2Data, function (obj) {
                  ngValue.push(obj[settings.id]);
                });

              } else {
                ngValue = select2Data[settings.id];
              }
            }
            ngModel.$setViewValue(ngValue);
          });

          // If user has requested notification, call function
          if (!!settings.select2 && typeof settings.select2.onChange === "function") {
            // Copy the passed in arguments
            var args = Array.prototype.slice.call(arguments);
            settings.select2.onChange.apply(element, args);
          }
        });

        //other stuff
        element.bind("$destroy", function () {
          element.select2("destroy");
        });

        // Expose the select2 element, for further customization
        if (typeof settings.onInitialized == "function") {
          settings.onInitialized.call(this, [element]);
        }
      }
    };
  }]);<commit_msg>Add a better check for an array.<commit_after>/**
 * @ngdoc directive
 * @name aaSelect2
 *
 * @description
 * Description place holder.
 **/

angular
  .module('aa.select2', [])
  .directive('aaSelect2', ['$q', function ($q) {
    'use strict';
    return {
      require: 'ngModel',
      template: '<input type="text" />',
      replace: true,
      link: function (scope, element, attrs, ngModel) {

        //util
        //assumes object is defined
        function isEmptyObject(obj) {
          if (!Object.keys) {  //<=IE 8
            return JSON.stringify(obj) === "{}";
          }

          return Object.keys(obj).length === 0;
        }

        //native select2 options directly from the user. always takes precedence
        //copy the object before we muck with it in case multiple select2s are sharing settings
        var settings = angular.copy(scope.$eval(attrs.aaSelect2));

        if (!angular.isObject(settings) || isEmptyObject(settings)) {
          throw 'aa-select2 options must be specified. Ex: <div aa-select2="*options here*"...\r\n';
        }

        //possible select2 options derived from user selections on settings
        var derivedOpts = {},

        //directive settings (aka nice wrapper for select2)
          inAjaxMode = settings ? angular.isFunction(settings.options) : false,
          inLocalArrayMode = settings ? angular.isArray(settings.options) : false,
          inIdMode = settings && settings.mode ? settings.mode.indexOf('id') !== -1 : false,
          inObjectMode = settings && settings.mode ? settings.mode.indexOf('object') !== -1 : false,
          inTagsMode = settings && settings.mode ? settings.mode.indexOf('tags') !== -1 : false,
          inThisMode = settings && settings.id === "@this" && settings.text === "@this";

        //need a placeholder for allow clear to work
        //fix bug?/weird api odditiy
        if (settings.select2 && settings.select2.allowClear) {
          derivedOpts.placeholder = "Select...";
        }

        if (attrs.placeholder) {
          derivedOpts.placeholder = attrs.placeholder;
        }

        //configure select2's options per passed settings
        if (settings) {

          if (inThisMode) {
            settings.id = 'id';
            settings.text = 'text';
          } else {
            settings.id = settings.id || 'id';
            settings.text = settings.text || 'text';
          }

          //have 'options' client side in an array
          if (inLocalArrayMode) {
            derivedOpts.data = derivedOpts.data || {};
            derivedOpts.data.text = settings.text;

            if (inThisMode) {
              var newData = [];
              angular.forEach(settings.options, function (obj) {
                newData.push({id: obj, text: obj});
              });
              derivedOpts.data.results = newData;
            } else {
              derivedOpts.data.results = settings.options;
            }
          }

          //AJAX MODE
          //run a query to get options (search)
          if (inAjaxMode) {
            derivedOpts.query = function (query) {
              // TODO: Ought to handle the failure case, instead of spinning forever
              var queryResult = settings.options(query.term);
              // Assume if it's not a promise and is an array, it's data
              if (!queryResult.then && queryResult.hasOwnProperty["length"]) {
                query.callback({
                  results: queryResult,
                  text: settings.text
                });
              } else {
                queryResult.then(function (data) {
                  if (inThisMode) {
                    var newData = [];
                    angular.forEach(data, function (str) {
                      newData.push({id: str, text: str});
                    });
                    data = newData;
                  }
                  query.callback({
                    results: data,
                    text: settings.text
                  });
                });
              }
            };

            if (inIdMode) {
              derivedOpts.initSelection = function (e, callback) {

                if (!ngModel.$modelValue) {
                  return;
                }

                if (inThisMode && inTagsMode) {
                  var newData = [];
                  angular.forEach(ngModel.$modelValue, function (str) {
                    newData.push({id: str, text: str});
                  });
                  callback(newData);
                  return;

                }

                if (inThisMode) {
                  callback({id: ngModel.$modelValue, text: ngModel.$modelValue});
                  return;
                }

                //allow for multiple lookups in tags mode (or just one in other modes)
                var modelValueIsArray = angular.isArray(ngModel.$modelValue),
                  lookups = [];

                if (modelValueIsArray) {
                  angular.forEach(ngModel.$modelValue, function (val) {
                    lookups.push(settings.textLookup(val));
                  });
                } else {
                  lookups.push(settings.textLookup(ngModel.$modelValue));
                }

                //resolves promises and resolved values alike
                $q.all(lookups)
                  .then(function (results) {
                    function resultMapper(data) {
                      var result;
                      if (angular.isUndefined(data.data)) {
                        result = data;
                      } else {
                        result = data.data;
                      }

                      if (!angular.isObject(result)) {
                        //passed back just the text. resolve:
                        var newResult = {};
                        newResult[settings.id] = ngModel.$modelValue;
                        newResult[settings.text] = result;
                        result = newResult;
                      }
                      return result;
                    }

                    if (modelValueIsArray) {
                      var mappedResults = [];

                      angular.forEach(results, function (result) {
                        mappedResults.push(resultMapper(result));
                      });

                      callback(mappedResults);
                    } else {
                      callback(resultMapper(results[0]));
                    }

                  });
              };
            }
          }

          derivedOpts.id = settings.id;

          derivedOpts.formatSelection = function (obj) {
            return obj[settings.text];
          };
          derivedOpts.formatResult = function (obj) {
            return obj[settings.text];
          };

          if (inTagsMode) {
            derivedOpts.tags = ngModel.$modelValue || [];
          }

        }

        var staticOpts = {
          width: 'resolve'
        };

        //order of prescedence for passing into select2 native api:
        //static opts loses first
        //then derivedOpts (the facade for select2 API that was created above aka what makes this plugin easy)
        //finally any explicit user opts passed into settings as 'select2' will always win
        var opts = angular.extend(staticOpts, derivedOpts, settings.select2);

        //setup select2 with options
        element.select2(opts);

        //programmatic changes to the model
        ngModel.$render = function () {

          if (!ngModel.$modelValue) {
            element.select2('val', "");
            return;
          }

          if (inIdMode) {
            element.select2('val', ngModel.$modelValue);
          } else if (inObjectMode) {
            element.select2('data', ngModel.$modelValue);
          }
        };

        //when select2 changes
        element.bind("change", function () {
          scope.$apply(function () {
            var select2Data = element.select2('data');

            var ngValue = null;

            if (!select2Data) {
              ngValue = null;
            } else if (inObjectMode) {
              ngValue = select2Data;
            } else if (inIdMode) {

              if (angular.isArray(select2Data)) {

                ngValue = [];
                angular.forEach(select2Data, function (obj) {
                  ngValue.push(obj[settings.id]);
                });

              } else {
                ngValue = select2Data[settings.id];
              }
            }
            ngModel.$setViewValue(ngValue);
          });

          // If user has requested notification, call function
          if (!!settings.select2 && typeof settings.select2.onChange === "function") {
            // Copy the passed in arguments
            var args = Array.prototype.slice.call(arguments);
            settings.select2.onChange.apply(element, args);
          }
        });

        //other stuff
        element.bind("$destroy", function () {
          element.select2("destroy");
        });

        // Expose the select2 element, for further customization
        if (typeof settings.onInitialized == "function") {
          settings.onInitialized.call(this, [element]);
        }
      }
    };
  }]);<|endoftext|>