<commit_before>var ReactReduxContext = require('react-redux').ReactReduxContext
var useContext = require('react').useContext
var useEffect = require('react').useEffect
var useState = require('react').useState

function add (store, subscriptions) {
  if (!store.subscriptions) store.subscriptions = { }
  if (!store.subscribers) store.subscribers = { }

  return Promise.all(subscriptions.map(function (i) {
    var subscription = i[0]
    var json = i[1]
    if (!store.subscribers[json]) store.subscribers[json] = 0
    store.subscribers[json] += 1
    if (store.subscribers[json] === 1) {
      var action = Object.assign({ type: 'logux/subscribe' }, subscription)
      store.subscriptions[json] = store.dispatch.sync(action)
    }
    return store.subscriptions[json]
  }))
}

function remove (store, subscriptions) {
  subscriptions.forEach(function (i) {
    var subscription = i[0]
    var json = i[1]
    store.subscribers[json] -= 1
    if (store.subscribers[json] === 0) {
      var action = Object.assign({ type: 'logux/unsubscribe' }, subscription)
      store.log.add(action, { sync: true })
      delete store.subscriptions[json]
    }
  })
}

function useSubscription (channels, opts) {
  if (!opts) opts = { }

  var isSubscribing = useState(true)
  var store = useContext(opts.context || ReactReduxContext).store

  var subscriptions = channels.map(function (i) {
    var subscription = typeof i === 'string' ? { channel: i } : i
    return [subscription, JSON.stringify(subscription)]
  })

  var id = subscriptions.map(function (i) {
    return i[1]
  }).sort().join(' ')

  useEffect(function () {
    var updated = false
    add(store, subscriptions).then(function () {
      if (!updated) isSubscribing[1](false)
    })
    return function () {
      updated = true
      remove(store, subscriptions)
    }
  }, [id])

  return isSubscribing[0]
}

module.exports = useSubscription
<commit_msg>Add JSDoc for useSubscription<commit_after>var ReactReduxContext = require('react-redux').ReactReduxContext
var useContext = require('react').useContext
var useEffect = require('react').useEffect
var useState = require('react').useState

function add (store, subscriptions) {
  if (!store.subscriptions) store.subscriptions = { }
  if (!store.subscribers) store.subscribers = { }

  return Promise.all(subscriptions.map(function (i) {
    var subscription = i[0]
    var json = i[1]
    if (!store.subscribers[json]) store.subscribers[json] = 0
    store.subscribers[json] += 1
    if (store.subscribers[json] === 1) {
      var action = Object.assign({ type: 'logux/subscribe' }, subscription)
      store.subscriptions[json] = store.dispatch.sync(action)
    }
    return store.subscriptions[json]
  }))
}

function remove (store, subscriptions) {
  subscriptions.forEach(function (i) {
    var subscription = i[0]
    var json = i[1]
    store.subscribers[json] -= 1
    if (store.subscribers[json] === 0) {
      var action = Object.assign({ type: 'logux/unsubscribe' }, subscription)
      store.log.add(action, { sync: true })
      delete store.subscriptions[json]
    }
  })
}

/**
 * @typedef {object} Subscribe
 * @property {string} channel
 */

/**
 * @typedef {string|Subscribe} Channel
 */

/**
 * Hook to subscribe for channel during component render and unsubscribe
 * on component unmount.
 *
 * @param  {Channel[]} channels Channels to subscribe.
 * @param  {object}  [opts={}] Options.
 * @param  {Context} [opts.context] Context with the store.
 * @return {boolean} `true` during data loading.
 *
 * @example
 * const useSubscription = require('logux-redux/use-subscription')
 * const useSelector = require('react-redux').useSelector
 * const UserPage = ({ userId }) => {
 *   const isSubscribing = useSubscription(`user/${ userId }`)
 *   const user = useSelector(state => state.users.find(i => i.id === userId))
 *   if (isSubscribing) {
 *     return <Loader />
 *   } else {
 *     return <h1>{ user.name }</h1>
 *   }
 * }
 */
function useSubscription (channels, opts) {
  if (!opts) opts = { }

  var isSubscribing = useState(true)
  var store = useContext(opts.context || ReactReduxContext).store

  var subscriptions = channels.map(function (i) {
    var subscription = typeof i === 'string' ? { channel: i } : i
    return [subscription, JSON.stringify(subscription)]
  })

  var id = subscriptions.map(function (i) {
    return i[1]
  }).sort().join(' ')

  useEffect(function () {
    var updated = false
    add(store, subscriptions).then(function () {
      if (!updated) isSubscribing[1](false)
    })
    return function () {
      updated = true
      remove(store, subscriptions)
    }
  }, [id])

  return isSubscribing[0]
}

module.exports = useSubscription
<|endoftext|>


<commit_before>import { ALL, EACH } from '../util'

describe('The Extension page should', () => {
  beforeAll(ALL)
  afterAll(ALL)
  beforeEach(EACH)
  afterEach(EACH)

  it('execute the injected script after page loaded', async () => {
    await page.evaluate(() => {
      const editor = window.ace.edit('ace-editor')
      editor.session.setValue(`
console.log('abc')
document.querySelector('body').style.background = 'red'`)
    })
    await page.evaluate(() => {
      document.querySelectorAll('button')[6].click()
    })
    await page.waitForTimeout(100)
    const input = await page.$$('textarea')
    await input[1].evaluate((node) => (node.value = ''))
    await input[1].type(
      'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.11.0/underscore-min.js',
      { delay: 2 }
    )
    await page.waitForTimeout(100)
    const allButtons = await page.$$('button')
    await allButtons[allButtons.length - 1].click()
    await page.waitForTimeout(100)
    await page.$eval('button', (x) => x.click())

    const newPage = await browser.newPage()
    await newPage.goto('https://google.com')
    await newPage.bringToFront()
    const background = await newPage.$eval(
      'body',
      (node) => node.style.background
    )
    expect(background).toBe('red')
    expect(await newPage.$eval('body', (node) => window._.VERSION)).toBe(
      '1.11.0'
    )

    page.bringToFront()
    const buttons = await page.$$('button')
    await buttons[1].click()
    await page.waitForTimeout(500)
    const dialogButtons = await page.$$('.MuiDialogActions-root > button')
    expect(dialogButtons).toHaveLength(3)
    await dialogButtons[1].click()
  })
})
<commit_msg>Bump integration test wait time<commit_after>import { ALL, EACH } from '../util'

describe('The Extension page should', () => {
  beforeAll(ALL)
  afterAll(ALL)
  beforeEach(EACH)
  afterEach(EACH)

  it('execute the injected script after page loaded', async () => {
    await page.evaluate(() => {
      const editor = window.ace.edit('ace-editor')
      editor.session.setValue(`
console.log('abc')
document.querySelector('body').style.background = 'red'`)
    })
    await page.evaluate(() => {
      document.querySelectorAll('button')[6].click()
    })
    await page.waitForTimeout(500)
    const input = await page.$$('textarea')
    await input[1].evaluate((node) => (node.value = ''))
    await input[1].type(
      'https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.11.0/underscore-min.js',
      { delay: 2 }
    )
    await page.waitForTimeout(500)
    const allButtons = await page.$$('button')
    await allButtons[allButtons.length - 1].click()
    await page.waitForTimeout(500)
    await page.$eval('button', (x) => x.click())

    const newPage = await browser.newPage()
    await newPage.goto('https://google.com')
    await newPage.bringToFront()
    const background = await newPage.$eval(
      'body',
      (node) => node.style.background
    )
    expect(background).toBe('red')
    expect(await newPage.$eval('body', (node) => window._.VERSION)).toBe(
      '1.11.0'
    )

    page.bringToFront()
    const buttons = await page.$$('button')
    await buttons[1].click()
    await page.waitForTimeout(500)
    const dialogButtons = await page.$$('.MuiDialogActions-root > button')
    expect(dialogButtons).toHaveLength(3)
    await dialogButtons[1].click()
  })
})
<|endoftext|>


<commit_before>define('endianbuffer', function () {
  function EndianBuffer (buf) {
    this.endian = false;
    if (typeof buf === 'number') {
      this.buffer = new ArrayBuffer(buf);
    } else if (buf instanceof ArrayBuffer) {
      this.buffer = buf;
    } else if (buf instanceof EndianBuffer) {
      this.buffer = new ArrayBuffer(buf.length);
      buf.copy(this);
    } else if (typeof buf === 'string') {
      this.buffer = new ArrayBuffer(buf.length / 2);
    }
    this.dataview = new DataView(this.buffer, 0);
    if (typeof buf === 'string')
      for (var i = 0; i < buf.length; i += 2)
        this.writeUInt8(parseInt(buf.slice(i, i + 2), 16), i / 2);
  }

  EndianBuffer.prototype.__defineGetter__('length', function () {
    return this.buffer.byteLength;
  });

  EndianBuffer.prototype.copy = function (buffer, t_start, s_start, s_end) {
    t_start = t_start || 0;
    s_start = s_start || 0;
    s_end = s_end || Math.min(this.length, buffer.length);
    var length = s_end - s_start
      , src_arr = new Uint8Array(this.buffer, s_start, length)
      , dst_arr = new Uint8Array(buffer.buffer, t_start, length)
    dst_arr.set(src_arr);
    return length;
  }

  EndianBuffer.prototype.slice = function (start, end) {
    start = start || 0;
    end = end || this.length;
    var newb = new EndianBuffer(this.buffer.slice(start, end));
    newb.endian = this.endian;
    return newb;
  }

  EndianBuffer.prototype.toString = function (type, from, to) {
    switch (type) {
      case 'ascii':
        if ((!from) || (!to) || (to - from > 2000))
          console.log('break');
        var arr = new Uint8Array(this.buffer.slice(from, to))
          , str = '';
        for (var i = 0; i < arr.length; i++)
          str += String.fromCharCode(arr[i]);
        return str;
      case '2charb':
        if (((to - from) ^ 2) !== 0)
          throw new Error('String length should be multiple of two!');
        var arr = new Uint8Array(this.buffer.slice(from, to))
          , str = '';
        for (var i = 0; i < arr.length; i += 2)
          str += String.fromCharCode( (arr[i * 2] << 8) + arr[(i * 2) + 1] );
        return str;
      case 'hex':
        var arr = new Uint8Array(this.buffer.slice(from, to))
          , str = '';
        for (var i = 0; i < arr.length; i++)
          str += (arr[i] < 16 ? '0' : '') + arr[i].toString(16);
        return str;
      default:
        return null;
    }
  };

  (function (EndianBuffer) {
    var keys = ['Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Float32', 'Float64'];
    keys.forEach(function (key) {
      EndianBuffer.prototype['read' + key.replace('int', 'Int')] = function (offset) {
        return this.dataview['get' + key](offset, this.endian)
      }
      EndianBuffer.prototype['write' + key.replace('int', 'Int')] = function (value, offset) {
        return this.dataview['set' + key](offset, value, this.endian)
      }
    });
  })(EndianBuffer);

  EndianBuffer.prototype.write = function (string, offset, length, encoding) {
    offset = offset || 0;
    length = Math.min(string.length, (this.buffer.byteLength - offset), length);
    encoding = encoding || 'ascii';
    if (encoding !== 'ascii')
      throw new Error('Only ascii implemented');
    var arr = new Uint8Array(this.buffer, offset, length);
    for (var i = 0; i < length; i ++)
      arr[i] = string.charCodeAt(i);
    return length;
  }

  EndianBuffer.prototype.fill = function (value, start, end) {
    value = value || 0;
    start = start || 0;
    end = end || 0;
    var arr = new Uint8Array(this.buffer, start, end - start);
    for (var i = 0; i < arr.length; i++)
      arr[i] = value;
  }
  return EndianBuffer;
});
<commit_msg>Added static method to ensure Buffers are converted to EndianBuffers<commit_after>define('endianbuffer', function () {
  function EndianBuffer (buf) {
    this.endian = false;
    if (typeof buf === 'number') {
      this.buffer = new ArrayBuffer(buf);
    } else if (buf instanceof ArrayBuffer) {
      this.buffer = buf;
    } else if (buf instanceof EndianBuffer) {
      this.buffer = new ArrayBuffer(buf.length);
      buf.copy(this);
    } else if (typeof buf === 'string') {
      this.buffer = new ArrayBuffer(buf.length / 2);
    }
    this.dataview = new DataView(this.buffer, 0);
    if (typeof buf === 'string')
      for (var i = 0; i < buf.length; i += 2)
        this.writeUInt8(parseInt(buf.slice(i, i + 2), 16), i / 2);
  }

  EndianBuffer.prototype.__defineGetter__('length', function () {
    return this.buffer.byteLength;
  });

  EndianBuffer.prototype.copy = function (buffer, t_start, s_start, s_end) {
    t_start = t_start || 0;
    s_start = s_start || 0;
    s_end = s_end || Math.min(this.length, buffer.length);
    var length = s_end - s_start
      , src_arr = new Uint8Array(this.buffer, s_start, length)
      , dst_arr = new Uint8Array(buffer.buffer, t_start, length)
    dst_arr.set(src_arr);
    return length;
  }

  EndianBuffer.prototype.slice = function (start, end) {
    start = start || 0;
    end = end || this.length;
    var newb = new EndianBuffer(this.buffer.slice(start, end));
    newb.endian = this.endian;
    return newb;
  }

  EndianBuffer.prototype.toString = function (type, from, to) {
    switch (type) {
      case 'ascii':
        if ((!from) || (!to) || (to - from > 2000))
          console.log('break');
        var arr = new Uint8Array(this.buffer.slice(from, to))
          , str = '';
        for (var i = 0; i < arr.length; i++)
          str += String.fromCharCode(arr[i]);
        return str;
      case '2charb':
        if (((to - from) ^ 2) !== 0)
          throw new Error('String length should be multiple of two!');
        var arr = new Uint8Array(this.buffer.slice(from, to))
          , str = '';
        for (var i = 0; i < arr.length; i += 2)
          str += String.fromCharCode( (arr[i * 2] << 8) + arr[(i * 2) + 1] );
        return str;
      case 'hex':
        var arr = new Uint8Array(this.buffer.slice(from, to))
          , str = '';
        for (var i = 0; i < arr.length; i++)
          str += (arr[i] < 16 ? '0' : '') + arr[i].toString(16);
        return str;
      default:
        return null;
    }
  };

  (function (EndianBuffer) {
    var keys = ['Int8', 'Uint8', 'Int16', 'Uint16', 'Int32', 'Uint32', 'Float32', 'Float64'];
    keys.forEach(function (key) {
      EndianBuffer.prototype['read' + key.replace('int', 'Int')] = function (offset) {
        return this.dataview['get' + key](offset, this.endian)
      }
      EndianBuffer.prototype['write' + key.replace('int', 'Int')] = function (value, offset) {
        return this.dataview['set' + key](offset, value, this.endian)
      }
    });
  })(EndianBuffer);

  EndianBuffer.prototype.write = function (string, offset, length, encoding) {
    offset = offset || 0;
    length = Math.min(string.length, (this.buffer.byteLength - offset), length);
    encoding = encoding || 'ascii';
    if (encoding !== 'ascii')
      throw new Error('Only ascii implemented');
    var arr = new Uint8Array(this.buffer, offset, length);
    for (var i = 0; i < length; i ++)
      arr[i] = string.charCodeAt(i);
    return length;
  }

  EndianBuffer.prototype.fill = function (value, start, end) {
    value = value || 0;
    start = start || 0;
    end = end || 0;
    var arr = new Uint8Array(this.buffer, start, end - start);
    for (var i = 0; i < arr.length; i++)
      arr[i] = value;
  }

  EndianBuffer.ensure = function (obj_arr) {
    if (Array.isArray(obj_arr)) {
      obj_arr.forEach(function (v, i, a) {
        if (v instanceof ArrayBuffer)
          a[i] = new EndianBuffer(v);
      });
    } else {
      var a = obj_arr;
      Object.keys(obj_arr).forEach(function (i) {
        var v = obj_arr[i];
        if (v instanceof ArrayBuffer)
          a[i] = new EndianBuffer(v);
      });
    }
  }

  return EndianBuffer;
});
<|endoftext|>


<commit_before>'use strict';
var nodeHelpers = require('./node-helpers'),
    scopeHelpers = require('./scope-helpers'),
    scopeTraverse = require('./scope-traverse');

module.exports = function(code) {

  var depth = 0,
      result = [];

  scopeTraverse(code, {

    leave: function(node, scope) {
      depth--;
    },

    enter: function(node, scope) {

      var args,
          name,
          variables,
          tabs,
          scopeResult = [];

      scopeResult.push(nodeHelpers.getFunctionString(node));

      variables = scopeHelpers.getScopeVariablesWithoutArguments(scope);

      scopeResult = scopeResult.concat(

        variables.filter(function eachVariable(variable) {
          return variable.name !== 'arguments' && variable.defs[0].type !== 'FunctionName';
        }).map(function eachVariable(variable) {
          return '- var ' + variable.name;
        }),

        scope.references.filter(function filterReferences(reference) {
          // If it's not resolved, it's an implicit global
          return reference.resolved;
        }).filter(function filterReferences(reference) {
          // Already declared in the variables above
          return reference.resolved.scope !== scope;
        }).map(function eachReference(reference) {
          return '- ' + reference.identifier.name + ' = ' + '?';
        })

      );

      tabs = Array(depth + 1).join('\t');
      result = result.concat(scopeResult.map(function mapScopeResults(resultLine) {
        return tabs + resultLine;
      }));

      depth++;
    }
  });

  return result.join('\n');

}
<commit_msg>Don't filter out references to globally scoped vars<commit_after>'use strict';
var nodeHelpers = require('./node-helpers'),
    scopeHelpers = require('./scope-helpers'),
    scopeTraverse = require('./scope-traverse');

module.exports = function(code) {

  var depth = 0,
      result = [];

  scopeTraverse(code, {

    leave: function(node, scope) {
      depth--;
    },

    enter: function(node, scope) {

      var args,
          name,
          variables,
          tabs,
          scopeResult = [];

      scopeResult.push(nodeHelpers.getFunctionString(node));

      variables = scopeHelpers.getScopeVariablesWithoutArguments(scope);

      scopeResult = scopeResult.concat(

        variables.filter(function eachVariable(variable) {
          return variable.name !== 'arguments' && variable.defs[0].type !== 'FunctionName';
        }).map(function eachVariable(variable) {
          return '- var ' + variable.name;
        }),

        scope.references.filter(function filterReferences(reference) {
          // If it's not resolved, it's an implicit global
          return !reference.resolved
                 // Already declared in the variables above
                 || reference.resolved.scope !== scope;;
        }).map(function eachReference(reference) {
          return '- ' + reference.identifier.name + ' = ' + '?';
        })

      );

      tabs = Array(depth + 1).join('\t');
      result = result.concat(scopeResult.map(function mapScopeResults(resultLine) {
        return tabs + resultLine;
      }));

      depth++;
    }
  });

  return result.join('\n');

}
<|endoftext|>


<commit_before>if (typeof String.prototype.startsWith != 'function') {
    String.prototype.startsWith = function (str){
        return this.slice(0, str.length) == str;
    };
}

function clearSearch() {
    $('#tree').treeview('clearSearch');
    $('#input-search').val('');
}

$(function() {
    var content = $("#content");
    //set up hash detection
    $(window).bind( 'hashchange', function(e) {
        var hash = location.hash;
        if (hash.startsWith("#page=")) {
            var type = hash.substring(6, hash.length);
            if (type !== "") {
                var lastPage = localStorage.getItem("lastPage");
                if (lastPage == "search") {
                    clearSearch();
                }
                localStorage.setItem("lastPage", "page");
                document.title = type;
                content.load(type + ".html");
                $.each($('#tree').treeview(true).getUnselected(), function (key, value) {
                    if (hash === value.href) {
                        var $tree = $('#tree');
                        $tree.treeview('selectNode', [value.nodeId, {silent: true}]);
                        $tree.treeview('revealNode', [ value.nodeId, { silent: true } ]);
                    }
                });
                return;
            }
        } else if (hash.startsWith("#search=")) {
            var pattern = hash.substring(8, hash.length);
            if (pattern !== "") {
                localStorage.setItem("lastPage", "search");
                document.title = "Search Results for " + pattern;
                var options = {
                    ignoreCase: true,
                    exactMatch: false,
                    revealResults: false
                };
                var $tree = $('#tree');
                var results = $tree.treeview('search', [ pattern, options ]);
                var output = '
' + results.length + ' matches found
\n';
                output += '
\n';
                $.each(results, function (index, result) {
                    output += '
' + result.text + '\n';
                });
                output += '
\n';
                $('#content').html(output);
                $('#input-search').val(pattern);
                return;
            }
        }
        location.hash = '#page=main';
        document.title = 'Protocol Documentation';
        content.load("main.html");
        clearSearch();
    });
    $(window).trigger( 'hashchange' );
});

$("#input-search").keyup(function(event){
    if(event.keyCode == 13){
        $("#btn-search").click();
    }
});

$('#btn-search').on('click', function(e) {
    var pattern = $('#input-search').val();
    window.location.hash = '#search=' + pattern;
});

var tree = $('#tree');

tree.treeview({
    data: getTree(),
    showBorder: false,
    showTags: true,
    color: "#428bca"
});

tree.on('nodeSelected', function(event, data) {
    window.location.hash = data.href;
});<commit_msg>HTML Template<commit_after>if (typeof String.prototype.startsWith != 'function') {
    String.prototype.startsWith = function (str){
        return this.slice(0, str.length) == str;
    };
}

function clearSearch() {
    $('#tree').treeview('clearSearch');
    $('#input-search').val('');
}

$(function() {
    var content = $("#content");
    //set up hash detection
    $(window).bind( 'hashchange', function(e) {
        var hash = location.hash;
        if (hash.startsWith("#page=")) {
            var type = hash.substring(6, hash.length);
            if (type !== "") {
                var lastPage = localStorage.getItem("lastPage");
                if (lastPage == "search") {
                    clearSearch();
                }
                localStorage.setItem("lastPage", "page");
                document.title = type;
                content.load(type + ".html");
                $.each($('#tree').treeview(true).getUnselected(), function (key, value) {
                    if (hash === value.href) {
                        var $tree = $('#tree');
                        $tree.treeview('selectNode', [value.nodeId, {silent: true}]);
                        $tree.treeview('revealNode', [ value.nodeId, { silent: true } ]);
                    }
                });
                return;
            }
        } else if (hash.startsWith("#search=")) {
            var pattern = hash.substring(8, hash.length);
            if (pattern !== "") {
                localStorage.setItem("lastPage", "search");
                document.title = "Search Results for " + pattern;
                var options = {
                    ignoreCase: true,
                    exactMatch: false,
                    revealResults: true
                };
                var $tree = $('#tree');
                var results = $tree.treeview('search', [ pattern, options ]);
                var output = '
' + results.length + ' matches found
\n';
                output += '
\n';
                $.each(results, function (index, result) {
                    output += '
' + result.text + '\n';
                });
                output += '
\n';
                $('#content').html(output);
                $('#input-search').val(pattern);
                return;
            }
        }
        location.hash = '#page=main';
        document.title = 'Protocol Documentation';
        content.load("main.html");
        clearSearch();
    });
    $(window).trigger( 'hashchange' );
});

$("#input-search").keyup(function(event){
    if(event.keyCode == 13){
        $("#btn-search").click();
    }
});

$('#btn-search').on('click', function(e) {
    var pattern = $('#input-search').val();
    window.location.hash = '#search=' + pattern;
});

var tree = $('#tree');

tree.treeview({
    data: getTree(),
    showBorder: false,
    showTags: true,
    color: "#428bca"
});

tree.on('nodeSelected', function(event, data) {
    window.location.hash = data.href;
});<|endoftext|>


<commit_before>'use strict';

const path = require('path');
const decompress = require('decompress');
const select = require('xpath.js');
const { DOMParser } = require('xmldom');
const got = require('got');

/**
 * Validates a package
 *
 * @param {String} file - Path to a zip package file
 * @returns {Promise<String[]>} Resolves to a list of error messages
 */
async function validatePackage(file) {
	const validationMessages = [];
	try {
		const files = await decompress(file);
		const manifestFiles = files.filter(
			file => path.extname(file.path) === '.dnn'
		);
		if (manifestFiles.length > 1) {
			return ['Too many .dnn manifest files'];
		} else if (manifestFiles.length === 0) {
			return ['Missing .dnn manifest file'];
		}

		const manifestFile = manifestFiles[0];
		const manifestContents = manifestFile.data.toString('utf-8');
		const parser = new DOMParser();

		const doc = parser.parseFromString(manifestContents);
		const cdnPathNodes = select(
			doc,
			'/dotnetnuke/packages/package/components/component/javaScriptLibrary/CDNPath/text()'
		);
		const cdnResponses = cdnPathNodes
			.map(({ data }) => data)
			.filter(data => Boolean(data))
			.map(url => got.head(url));
		for (const response of cdnResponses) {
			try {
				await response;
			} catch (e) {
				validationMessages.push('Error checking CDN URL: ' + e);
			}
		}

		const fileNames = select(
			doc,
			'/dotnetnuke/packages/package/components/component/javaScriptLibrary/fileName/text()'
		).map(({ data }) => data);
		if (fileNames.length !== 1) {
			validationMessages.push(
				'Expected exactly one JavaScript_Library component file name, got ' +
					fileNames.length
			);
		}

		const jsFileNames = select(
			doc,
			'/dotnetnuke/packages/package/components/component/jsfiles/jsfile/name/text()'
		).map(({ data }) => data);
		if (jsFileNames.length !== 1) {
			validationMessages.push(
				'Expected exactly one JavaScriptFile component file name, got ' +
					jsFileNames.length
			);
		}

		if (
			fileNames.length === 1 &&
			jsFileNames.length === 1 &&
			fileNames[0] !== jsFileNames[0]
		) {
			validationMessages.push(
				`Expected JavaScriptFile component file name "${
					jsFileNames[0]
				}" to equal JavaScript_Library component file name "${
					fileNames[0]
				}"`
			);
		}

		return validationMessages;
	} catch (e) {
		validationMessages.push('Unexpected error: ' + e);
		return validationMessages;
	}
}

module.exports = {
	validatePackage,
};
<commit_msg>Validate that specified files are in the package<commit_after>'use strict';

const path = require('path');
const decompress = require('decompress');
const select = require('xpath.js');
const { DOMParser } = require('xmldom');
const got = require('got');

function equalCaseInsensitive(a, b) {
	if (!a || !b) {
		return !a && !b;
	}

	return a.toUpperCase() === b.toUpperCase();
}

/**
 * Validates a package
 *
 * @param {String} file - Path to a zip package file
 * @returns {Promise<String[]>} Resolves to a list of error messages
 */
async function validatePackage(file) {
	const validationMessages = [];
	try {
		const files = await decompress(file);
		const manifestFiles = files.filter(
			file => path.extname(file.path) === '.dnn'
		);
		if (manifestFiles.length > 1) {
			return ['Too many .dnn manifest files'];
		} else if (manifestFiles.length === 0) {
			return ['Missing .dnn manifest file'];
		}

		const manifestFile = manifestFiles[0];
		const manifestContents = manifestFile.data.toString('utf-8');
		const parser = new DOMParser();

		const doc = parser.parseFromString(manifestContents);
		const cdnPathNodes = select(
			doc,
			'/dotnetnuke/packages/package/components/component/javaScriptLibrary/CDNPath/text()'
		);
		const cdnResponses = cdnPathNodes
			.map(({ data }) => data)
			.filter(data => Boolean(data))
			.map(url => got.head(url));
		for (const response of cdnResponses) {
			try {
				await response;
			} catch (e) {
				validationMessages.push('Error checking CDN URL: ' + e);
			}
		}

		const fileNames = select(
			doc,
			'/dotnetnuke/packages/package/components/component/javaScriptLibrary/fileName/text()'
		).map(({ data }) => data);
		if (fileNames.length !== 1) {
			validationMessages.push(
				'Expected exactly one JavaScript_Library component file name, got ' +
					fileNames.length
			);
		}

		const jsFileNames = select(
			doc,
			'/dotnetnuke/packages/package/components/component/jsfiles/jsfile/name/text()'
		).map(({ data }) => data);
		if (jsFileNames.length !== 1) {
			validationMessages.push(
				'Expected exactly one JavaScriptFile component file name, got ' +
					jsFileNames.length
			);
		}

		if (
			fileNames.length === 1 &&
			jsFileNames.length === 1 &&
			fileNames[0] !== jsFileNames[0]
		) {
			validationMessages.push(
				`Expected JavaScriptFile component file name "${
					jsFileNames[0]
				}" to equal JavaScript_Library component file name "${
					fileNames[0]
				}"`
			);
		} else {
			const fileName = fileNames[0];
			const jsFiles = files.filter(file =>
				equalCaseInsensitive(fileName, path.basename(file.path))
			);
			if (jsFiles.length === 0) {
				validationMessages.push(
					`File in manifest "${fileName}" is not in package zip`
				);
			}
		}

		return validationMessages;
	} catch (e) {
		validationMessages.push('Unexpected error: ' + e);
		return validationMessages;
	}
}

module.exports = {
	validatePackage,
};
<|endoftext|>


<commit_before>describe('Type transform menu controller', function () {
    'use strict';

    var createController, scope;
    var currentMetadata = {id: '719b84635c436ef245'};

    var types = [
        {'id': 'ANY', 'name': 'any', 'labelKey': 'ANY'},
        {'id': 'STRING', 'name': 'string', 'labelKey': 'STRING'},
        {'id': 'NUMERIC', 'name': 'numeric', 'labelKey': 'NUMERIC'},
        {'id': 'INTEGER', 'name': 'integer', 'labelKey': 'INTEGER'},
        {'id': 'DOUBLE', 'name': 'double', 'labelKey': 'DOUBLE'},
        {'id': 'FLOAT', 'name': 'float', 'labelKey': 'FLOAT'},
        {'id': 'BOOLEAN', 'name': 'boolean', 'labelKey': 'BOOLEAN'},
        {'id': 'DATE', 'name': 'date', 'labelKey': 'DATE'}
    ];

    beforeEach(module('data-prep.type-transformation-menu'));

    beforeEach(inject(function ($rootScope, $controller, $q, state, ColumnTypesService) {
        scope = $rootScope.$new();
        createController = function () {
            var ctrl = $controller('TypeTransformMenuCtrl', {
                $scope: scope
            });
            ctrl.column = {
                id: '0001',
                domain: 'CITY',
                domainLabel: 'CITY',
                domainFrequency: 18,
                type: 'string',
                semanticDomains: [
                    {id: '', label: '', frequency: 15},
                    {id: 'CITY', label: 'CITY', frequency: 18},
                    {id: 'REGION', label: 'REGION', frequency: 6},
                    {id: 'COUNTRY', label: 'COUNTRY', frequency: 17}
                ]
            };
            return ctrl;
        };

        state.playground.dataset = currentMetadata;
        spyOn(ColumnTypesService, 'getTypes').and.returnValue($q.when(types));
    }));

    it('should get column primitive types', inject(function (ColumnTypesService) {
        //when
        var ctrl = createController();
        scope.$digest();

        //then
        expect(ColumnTypesService.getTypes).toHaveBeenCalled();
        expect(ctrl.types).toBe(types);
    }));

    it('should change domain locally and call backend', inject(function ($q, DatasetService) {
        //given
        spyOn(DatasetService, 'updateColumn').and.returnValue($q.when(null));
        var ctrl = createController();
        var newDomain = {
            id: 'COUNTRY',
            label: 'COUNTRY',
            frequency: 17
        };

        //when
        ctrl.changeDomain(newDomain);

        //then
        expect(ctrl.column.domain).toBe('COUNTRY');
        expect(ctrl.column.domainLabel).toBe('COUNTRY');
        expect(ctrl.column.domainFrequency).toBe(17);
        expect(ctrl.currentDomain).toBe('COUNTRY');
        expect(ctrl.currentSimplifiedDomain).toBe('COUNTRY');
        expect(DatasetService.updateColumn).toHaveBeenCalledWith(currentMetadata.id, '0001', {domain: 'COUNTRY'});
    }));

    it('should revert domain when backend return error', inject(function ($q, DatasetService) {
        //given
        spyOn(DatasetService, 'updateColumn').and.returnValue($q.reject(null));
        var ctrl = createController();
        var newDomain = {
            id: 'COUNTRY',
            label: 'COUNTRY',
            frequency: 17
        };

        //when
        ctrl.changeDomain(newDomain);
        scope.$digest();

        //then
        expect(ctrl.column.domain).toBe('CITY');
        expect(ctrl.column.domainLabel).toBe('CITY');
        expect(ctrl.column.domainFrequency).toBe(18);
        expect(ctrl.currentDomain).toBe('CITY');
        expect(ctrl.currentSimplifiedDomain).toBe('CITY');
    }));

    it('should change type and clear domain locally and call backend', inject(function ($q, PlaygroundService) {
        //given
        spyOn(PlaygroundService, 'updateColumn').and.returnValue($q.when(null));
        var ctrl = createController();
        var newType = {
            id: 'integer'
        };

        //when
        ctrl.changeType(newType);

        //then
        expect(ctrl.column.type).toBe('integer');
        expect(ctrl.column.domain).toBe('');
        expect(ctrl.column.domainLabel).toBe('');
        expect(ctrl.column.domainFrequency).toBe(0);
        expect(ctrl.currentDomain).toBe('INTEGER');
        expect(ctrl.currentSimplifiedDomain).toBe('number');
        expect(PlaygroundService.updateColumn).toHaveBeenCalledWith('0001', 'integer', '');
    }));

    it('should revert type and domain when backend return error', inject(function ($q, PlaygroundService) {
        //given
        spyOn(PlaygroundService, 'updateColumn').and.returnValue($q.reject(null));
        var ctrl = createController();
        var newType = {
            id: 'integer'
        };

        //when
        ctrl.changeType(newType);
        scope.$digest();

        //then
        expect(ctrl.column.type).toBe('string');
        expect(ctrl.column.domain).toBe('CITY');
        expect(ctrl.column.domainLabel).toBe('CITY');
        expect(ctrl.column.domainFrequency).toBe(18);
        expect(ctrl.currentDomain).toBe('CITY');
        expect(ctrl.currentSimplifiedDomain).toBe('CITY');
    }));

    it('should filter concrete domain and order them', function () {
        //given
        var ctrl = createController();

        //when
        ctrl.adaptDomains();

        //then
        expect(ctrl.domains).toEqual([
            {id: 'CITY', label: 'CITY', frequency: 18},
            {id: 'COUNTRY', label: 'COUNTRY', frequency: 17},
            {id: 'REGION', label: 'REGION', frequency: 6}
        ]);
        expect(ctrl.currentDomain).toBe('CITY');
        expect(ctrl.currentSimplifiedDomain).toBe('CITY');
    });
});<commit_msg>[TDP-446] fix TUs<commit_after>describe('Type transform menu controller', function () {
    'use strict';

    var createController, scope;
    var currentMetadata = {id: '719b84635c436ef245'};

    var types = [
        {'id': 'ANY', 'name': 'any', 'labelKey': 'ANY'},
        {'id': 'STRING', 'name': 'string', 'labelKey': 'STRING'},
        {'id': 'NUMERIC', 'name': 'numeric', 'labelKey': 'NUMERIC'},
        {'id': 'INTEGER', 'name': 'integer', 'labelKey': 'INTEGER'},
        {'id': 'DOUBLE', 'name': 'double', 'labelKey': 'DOUBLE'},
        {'id': 'FLOAT', 'name': 'float', 'labelKey': 'FLOAT'},
        {'id': 'BOOLEAN', 'name': 'boolean', 'labelKey': 'BOOLEAN'},
        {'id': 'DATE', 'name': 'date', 'labelKey': 'DATE'}
    ];

    beforeEach(module('data-prep.type-transformation-menu'));

    beforeEach(inject(function ($rootScope, $controller, $q, state, ColumnTypesService) {
        scope = $rootScope.$new();
        createController = function () {
            var ctrl = $controller('TypeTransformMenuCtrl', {
                $scope: scope
            });
            ctrl.column = {
                id: '0001',
                domain: 'CITY',
                domainLabel: 'CITY',
                domainFrequency: 18,
                type: 'string',
                semanticDomains: [
                    {id: '', label: '', frequency: 15},
                    {id: 'CITY', label: 'CITY', frequency: 18},
                    {id: 'REGION', label: 'REGION', frequency: 6},
                    {id: 'COUNTRY', label: 'COUNTRY', frequency: 17}
                ]
            };
            return ctrl;
        };

        state.playground.dataset = currentMetadata;
        spyOn(ColumnTypesService, 'getTypes').and.returnValue($q.when(types));
    }));

    it('should get column primitive types', inject(function (ColumnTypesService) {
        //when
        var ctrl = createController();
        scope.$digest();

        //then
        expect(ColumnTypesService.getTypes).toHaveBeenCalled();
        expect(ctrl.types).toBe(types);
    }));

    it('should change domain locally and call backend to add a step', inject(function ($q, PlaygroundService) {
        //given
        spyOn(PlaygroundService, 'addUpdateColumnDomainStep').and.returnValue($q.when(null));
        var ctrl = createController();
        var newDomain = {
            id: 'COUNTRY',
            label: 'COUNTRY',
            frequency: 17
        };

        //when
        ctrl.changeDomain(newDomain);

        //then
        expect(ctrl.column.domain).toBe('COUNTRY');
        expect(ctrl.column.domainLabel).toBe('COUNTRY');
        expect(ctrl.column.domainFrequency).toBe(17);
        expect(ctrl.currentDomain).toBe('COUNTRY');
        expect(ctrl.currentSimplifiedDomain).toBe('COUNTRY');

        expect(PlaygroundService.addUpdateColumnDomainStep).toHaveBeenCalledWith('0001', {id: 'COUNTRY', label: 'COUNTRY', frequency: 17});
    }));

    it('should revert domain when backend return error', inject(function ($q, PlaygroundService) {
        //given
        spyOn(PlaygroundService, 'addUpdateColumnDomainStep').and.returnValue($q.reject(null));
        var ctrl = createController();
        var newDomain = {
            id: 'COUNTRY',
            label: 'COUNTRY',
            frequency: 17
        };

        //when
        ctrl.changeDomain(newDomain);
        scope.$digest();

        //then
        expect(ctrl.column.domain).toBe('CITY');
        expect(ctrl.column.domainLabel).toBe('CITY');
        expect(ctrl.column.domainFrequency).toBe(18);
        expect(ctrl.currentDomain).toBe('CITY');
        expect(ctrl.currentSimplifiedDomain).toBe('CITY');
    }));

    it('should change type and clear domain locally and call backend', inject(function ($q, PlaygroundService) {
        //given
        spyOn(PlaygroundService, 'addUpdateColumnTypeStep').and.returnValue($q.when(null));
        var ctrl = createController();
        var newType = {
            id: 'integer'
        };

        //when
        ctrl.changeType(newType);

        //then
        expect(ctrl.column.type).toBe('integer');
        expect(ctrl.column.domain).toBe('');
        expect(ctrl.column.domainLabel).toBe('');
        expect(ctrl.column.domainFrequency).toBe(0);
        expect(ctrl.currentDomain).toBe('INTEGER');
        expect(ctrl.currentSimplifiedDomain).toBe('number');
        expect(PlaygroundService.addUpdateColumnTypeStep).toHaveBeenCalledWith('0001', {id:'integer'});
    }));

    it('should revert type and domain when backend return error', inject(function ($q, PlaygroundService) {
        //given
        spyOn(PlaygroundService, 'addUpdateColumnTypeStep').and.returnValue($q.reject(null));
        var ctrl = createController();
        var newType = {
            id: 'integer'
        };

        //when
        ctrl.changeType(newType);
        scope.$digest();

        //then
        expect(ctrl.column.type).toBe('string');
        expect(ctrl.column.domain).toBe('CITY');
        expect(ctrl.column.domainLabel).toBe('CITY');
        expect(ctrl.column.domainFrequency).toBe(18);
        expect(ctrl.currentDomain).toBe('CITY');
        expect(ctrl.currentSimplifiedDomain).toBe('CITY');
    }));

    it('should filter concrete domain and order them', function () {
        //given
        var ctrl = createController();

        //when
        ctrl.adaptDomains();

        //then
        expect(ctrl.domains).toEqual([
            {id: 'CITY', label: 'CITY', frequency: 18},
            {id: 'COUNTRY', label: 'COUNTRY', frequency: 17},
            {id: 'REGION', label: 'REGION', frequency: 6}
        ]);
        expect(ctrl.currentDomain).toBe('CITY');
        expect(ctrl.currentSimplifiedDomain).toBe('CITY');
    });
});<|endoftext|>


<commit_before>;

import angular from 'angular';
import topNavModule from '../topnav';
import overviewTitleBarModule from '../visitor-title-bar';
import compareToModule from '../../directives/compareTo';
import accordionModule from '../accordion';
import flexGridModule from '../flexgrid';
import config from '../../config';
import {
    attach,
    scrollTo,
    delay,
} from '../../utils';
import { actionCreators }  from '../../actions/actions';
import {
    makeParams,
} from '../../configRouting.js';

const serviceDependencies = ['$ngRedux', '$scope', /*'$routeParams' /*injections as strings here*/];

const workGrid = [{imageSrc: 'generated/icon-sprite.svg#ico36_description', text: 'Post your need anonymously', detail: 'Needs can be very personal, so privacy is important. You don\'t have to reveal your identity here.'},
    {imageSrc: 'generated/icon-sprite.svg#ico36_match', text: 'Get matches', detail: 'Based on the' +
    ' information you provide, we will try to connect you with others'},
    {imageSrc: 'generated/icon-sprite.svg#ico36_incoming', text: 'Request contact', detail: 'If you\'re interested,' +
    ' make a contact request - or get one if your counterpart is faster than you', separatorText: 'or', text2: 'Be' +
    ' contacted'},
    {imageSrc: 'generated/icon-sprite.svg#ico36_message', text: 'Interact and exchange', detail: 'You found someone' +
    ' who has what you need, wants to meet or change something in your common environment? Go chat with them! '}];

const peopleGrid = [{imageSrc: 'images/face1.png', text: '"I have something to offer"'},
    {imageSrc: 'images/face2.png', text: '"I want something"'},
    {imageSrc: 'images/face3.png', text: '"I want to do something together"'},
    {imageSrc: 'images/face4.png', text: '"I want to change something"'}];

const questions = [
    {title: "Do I need to register?", detail: "Currently, you have to register, but we're working on a feature to" +
    " let you use the site without registering. You can also run your own server if you don't want to register here."},
    {title: "Is there a native mobile app?", detail: "No. The system is open source though. You can make one if" +
    " you like. Maybe one that talks to your own server? Contact us if you would like support in doing that!"},
    {title: "Who can view my posts?", detail: "Anyone can view your posts. (That's the idea!) Post-level access" +
    " control is definitely possible and interesting, but we have not designed that, yet. Contact us if you would" +
    " like to share your thoughts on how to do that."},
    {title: "What about my privacy?", detail: "All the data you provide in a need description is" +
    " public and unencrypted. All the messages in a conversation are unencrypted but only visible to us (operating" +
    " the" +
    " servers) and to you and your conversation partner."},
    {title: "Will the people I talk to see my identity?", detail: "If everything" +
    " works as intended, no. Each need has its own cryptographic identity. They will know that the person who" +
    " wrote the posting is the one sending them messages. As long as you do not provide any" +
    " information that identifies you, others will not easily find out who you really are. But please do not think" +
    " that you are fully anonymous here. Even if you are behind a proxy or an anonymization network, there might be" +
    " ways to de-anonymize you based on the data you provide."},
    {title: "I am offering goods/services on the Internet already. Can people find them here?",
        detail: "Yes! The idea is to have an open, decentralized infrastructure that makes it easy for anyone" +
        " to post what they seek or what they offer, and to find people to interact with. " +
        " You'll have to set up a WoN node or post your offerings to a service (like" +
        " matchat.org) that handles everything for you. We can help you with that."
    },
    {title: "Is this website production-ready?", detail :"No. Do not use it for anything important to you. It is a" +
    " demonstrator of a research project and running on modest hardware. We're working on it, though."},
    {title: "Is this website secure?", detail :"No. See below for more information."},
    {title: "Can I post whatever I want here?", detail :"No. Make sure it is legal, unoffensive, and that it pleases" +
    " us. We will delete any postings we do not like without prior notice, explanation, and there will be no way to" +
    " restore the data."},
    {title: "Are you selling my data?", detail :"No."},
    {title: "How is this different from the websites I already know?",
        detail: "Two-way matching: The person searching for something will find supply, the person offering something" +
        " will find demands. Genericity: The process (post/match/chat) is quite general and can be applied to a great" +
        " variety of cases. Here, we demonstrate a few, but we ask you to come up with more variations and build" +
        " your own applications on top of them. Openness: " +
        " If you want, you can set up your own website to host your own content using either our software or your" +
        " own implementation of the protocols. " +
        " Someone else can still find your content and interact with it from here because the two websites speak" +
        " the same protocol. You can also set up your own matching service to provide better matches. In both" +
        " cases, We will be glad to help if you want to try!"},
    {title: "How secure is this system?", detail:"tl;dr: Probably not very secure at the moment. As a general rule," +
    " try" +
    " not to post or write anything here you would not be happy to write on a postcard with your name on it. (By the" +
    " way, you should handle e-mail the same way.)" +
    " Here is how we" +
    " implemented it - in the bird's eye view: Your data is stored in clear text on our servers. The communication" +
    " between your browser and your counterpart's browser is relayed over at most four intermediate servers: your" +
    " Owner Application (https://matchat.org/owner/), your WoN node (https://matchat.org/won/), your" +
    " counterpart's WoN node and your counterpart's Owner Application. Each one of" +
    " these communication channels are secured with TLS, so the data is encrypted as it is transmitted. Once your" +
    " messages reach your Owner Application, they are signed using asymmetric cryptography so your counterpart can " +
    "verify that the message was written by the same person who created the need in the first place. As messages are" +
    " forwarded to the next processing node, signatures are added by " +
    "the receiving node. Messages sent later contain the signatures of earlier messages, so it becomes impossible " +
    "to change the content of messages or pretend they were never sent or received." +
    " The Owner Application creates a new key pair for every need you" +
    " create, so others should not be able to find out which needs are yours and which needs are from other" +
    " people. Note that this system has not had an independent security audit. If you are interested in" +
    " assessing the security of our approach, or if you have feedback for us, please contact us."},
    {title: "Is there a plug-in for [shop, marketplace, social network, forum] software X?", detail: "No." +
    " If you have an idea for an integration, or if you would like to help with one, let us know."}
];

class AboutController {
    constructor(/* arguments <- serviceDependencies */){
        attach(this, serviceDependencies, arguments);

        const self = this;
        this.config = config;
        this.makeParams = makeParams;

        const select = (state) => ({ });
        const disconnect = this.$ngRedux.connect(select, actionCreators)(this);

        this.$scope.$on('$destroy',disconnect);

        this.questions = questions;
        this.peopleGrid = peopleGrid;
        this.workGrid = workGrid;
        this.moreInfo = false;
    }

    toggleMoreInfo(){
        this.moreInfo = !this.moreInfo;
    }

    scrollToSignup(){
        console.error("TODO scrollToSignup not yet implemented");
    }
}

export default angular.module('won.owner.components.about', [
    overviewTitleBarModule,
    accordionModule,
    topNavModule,
    flexGridModule,
    compareToModule,
])
    .controller('AboutController', [...serviceDependencies, AboutController])
    .name;
<commit_msg>Removed some unused imports.<commit_after>;

import angular from 'angular';
import topNavModule from '../topnav';
import overviewTitleBarModule from '../visitor-title-bar';
import compareToModule from '../../directives/compareTo';
import accordionModule from '../accordion';
import flexGridModule from '../flexgrid';
import config from '../../config';
import {
    attach,
} from '../../utils';
import { actionCreators }  from '../../actions/actions';

const serviceDependencies = ['$ngRedux', '$scope', /*'$routeParams' /*injections as strings here*/];

const workGrid = [{imageSrc: 'generated/icon-sprite.svg#ico36_description', text: 'Post your need anonymously', detail: 'Needs can be very personal, so privacy is important. You don\'t have to reveal your identity here.'},
    {imageSrc: 'generated/icon-sprite.svg#ico36_match', text: 'Get matches', detail: 'Based on the' +
    ' information you provide, we will try to connect you with others'},
    {imageSrc: 'generated/icon-sprite.svg#ico36_incoming', text: 'Request contact', detail: 'If you\'re interested,' +
    ' make a contact request - or get one if your counterpart is faster than you', separatorText: 'or', text2: 'Be' +
    ' contacted'},
    {imageSrc: 'generated/icon-sprite.svg#ico36_message', text: 'Interact and exchange', detail: 'You found someone' +
    ' who has what you need, wants to meet or change something in your common environment? Go chat with them! '}];

const peopleGrid = [{imageSrc: 'images/face1.png', text: '"I have something to offer"'},
    {imageSrc: 'images/face2.png', text: '"I want something"'},
    {imageSrc: 'images/face3.png', text: '"I want to do something together"'},
    {imageSrc: 'images/face4.png', text: '"I want to change something"'}];

const questions = [
    {title: "Do I need to register?", detail: "Currently, you have to register, but we're working on a feature to" +
    " let you use the site without registering. You can also run your own server if you don't want to register here."},
    {title: "Is there a native mobile app?", detail: "No. The system is open source though. You can make one if" +
    " you like. Maybe one that talks to your own server? Contact us if you would like support in doing that!"},
    {title: "Who can view my posts?", detail: "Anyone can view your posts. (That's the idea!) Post-level access" +
    " control is definitely possible and interesting, but we have not designed that, yet. Contact us if you would" +
    " like to share your thoughts on how to do that."},
    {title: "What about my privacy?", detail: "All the data you provide in a need description is" +
    " public and unencrypted. All the messages in a conversation are unencrypted but only visible to us (operating" +
    " the" +
    " servers) and to you and your conversation partner."},
    {title: "Will the people I talk to see my identity?", detail: "If everything" +
    " works as intended, no. Each need has its own cryptographic identity. They will know that the person who" +
    " wrote the posting is the one sending them messages. As long as you do not provide any" +
    " information that identifies you, others will not easily find out who you really are. But please do not think" +
    " that you are fully anonymous here. Even if you are behind a proxy or an anonymization network, there might be" +
    " ways to de-anonymize you based on the data you provide."},
    {title: "I am offering goods/services on the Internet already. Can people find them here?",
        detail: "Yes! The idea is to have an open, decentralized infrastructure that makes it easy for anyone" +
        " to post what they seek or what they offer, and to find people to interact with. " +
        " You'll have to set up a WoN node or post your offerings to a service (like" +
        " matchat.org) that handles everything for you. We can help you with that."
    },
    {title: "Is this website production-ready?", detail :"No. Do not use it for anything important to you. It is a" +
    " demonstrator of a research project and running on modest hardware. We're working on it, though."},
    {title: "Is this website secure?", detail :"No. See below for more information."},
    {title: "Can I post whatever I want here?", detail :"No. Make sure it is legal, unoffensive, and that it pleases" +
    " us. We will delete any postings we do not like without prior notice, explanation, and there will be no way to" +
    " restore the data."},
    {title: "Are you selling my data?", detail :"No."},
    {title: "How is this different from the websites I already know?",
        detail: "Two-way matching: The person searching for something will find supply, the person offering something" +
        " will find demands. Genericity: The process (post/match/chat) is quite general and can be applied to a great" +
        " variety of cases. Here, we demonstrate a few, but we ask you to come up with more variations and build" +
        " your own applications on top of them. Openness: " +
        " If you want, you can set up your own website to host your own content using either our software or your" +
        " own implementation of the protocols. " +
        " Someone else can still find your content and interact with it from here because the two websites speak" +
        " the same protocol. You can also set up your own matching service to provide better matches. In both" +
        " cases, We will be glad to help if you want to try!"},
    {title: "How secure is this system?", detail:"tl;dr: Probably not very secure at the moment. As a general rule," +
    " try" +
    " not to post or write anything here you would not be happy to write on a postcard with your name on it. (By the" +
    " way, you should handle e-mail the same way.)" +
    " Here is how we" +
    " implemented it - in the bird's eye view: Your data is stored in clear text on our servers. The communication" +
    " between your browser and your counterpart's browser is relayed over at most four intermediate servers: your" +
    " Owner Application (https://matchat.org/owner/), your WoN node (https://matchat.org/won/), your" +
    " counterpart's WoN node and your counterpart's Owner Application. Each one of" +
    " these communication channels are secured with TLS, so the data is encrypted as it is transmitted. Once your" +
    " messages reach your Owner Application, they are signed using asymmetric cryptography so your counterpart can " +
    "verify that the message was written by the same person who created the need in the first place. As messages are" +
    " forwarded to the next processing node, signatures are added by " +
    "the receiving node. Messages sent later contain the signatures of earlier messages, so it becomes impossible " +
    "to change the content of messages or pretend they were never sent or received." +
    " The Owner Application creates a new key pair for every need you" +
    " create, so others should not be able to find out which needs are yours and which needs are from other" +
    " people. Note that this system has not had an independent security audit. If you are interested in" +
    " assessing the security of our approach, or if you have feedback for us, please contact us."},
    {title: "Is there a plug-in for [shop, marketplace, social network, forum] software X?", detail: "No." +
    " If you have an idea for an integration, or if you would like to help with one, let us know."}
];

class AboutController {
    constructor(/* arguments <- serviceDependencies */){
        attach(this, serviceDependencies, arguments);

        const self = this;
        this.config = config;

        const select = (state) => ({ });
        const disconnect = this.$ngRedux.connect(select, actionCreators)(this);

        this.$scope.$on('$destroy',disconnect);

        this.questions = questions;
        this.peopleGrid = peopleGrid;
        this.workGrid = workGrid;
        this.moreInfo = false;
    }

    toggleMoreInfo(){
        this.moreInfo = !this.moreInfo;
    }

    scrollToSignup(){
        console.error("TODO scrollToSignup not yet implemented");
    }
}

export default angular.module('won.owner.components.about', [
    overviewTitleBarModule,
    accordionModule,
    topNavModule,
    flexGridModule,
    compareToModule,
])
    .controller('AboutController', [...serviceDependencies, AboutController])
    .name;
<|endoftext|>


<commit_before>Polymer('element-slider', {
  counter: 0,
  touchDown: null,

  domReady: function() {
    this.children[0].setAttribute('active', '')
  },

  showCurrent: function() {
    var item = Math.abs(this.counter % this.children.length);
    this.eachSlide(function(slide) {
      slide.removeAttribute('active');
    });
    this.children[item].setAttribute('active', '');
  },

  next: function() {
    console.log('next');
    this.counter++;
    this.showCurrent();
  },

  prev: function() {
    console.log('prev');
    this.counter--;
    this.showCurrent();
  },

  initTouch: function(evnt) {
    this.touchDown = evnt.touches[0];
  },

  touchMove: function(evnt) {
    if (!this.touchDown) return;

    var touchDown = this.touchDown,
    touchUp = evnt.touches[0];

    var diff = {
      x: touchDown.clientX - touchUp.clientX,
      y: touchDown.clientY - touchUp.clientY
    }

    // We're only tracking left/right swiping.
    if (Math.abs(diff.x) > Math.abs(diff.y)) {
      if (diff.x > 0) this.next();
      else this.prev();
    }

    this.touchDown = null;
  },

  eachSlide: function(callback) {
    [].forEach.call(this.children, callback);
  }
});
<commit_msg>Remove console messages<commit_after>Polymer('element-slider', {
  counter: 0,
  touchDown: null,

  domReady: function() {
    this.children[0].setAttribute('active', '')
  },

  showCurrent: function() {
    var item = Math.abs(this.counter % this.children.length);
    this.eachSlide(function(slide) {
      slide.removeAttribute('active');
    });
    this.children[item].setAttribute('active', '');
  },

  next: function() {
    this.counter++;
    this.showCurrent();
  },

  prev: function() {
    this.counter--;
    this.showCurrent();
  },

  initTouch: function(evnt) {
    this.touchDown = evnt.touches[0];
  },

  touchMove: function(evnt) {
    if (!this.touchDown) return;

    var touchDown = this.touchDown,
    touchUp = evnt.touches[0];

    var diff = {
      x: touchDown.clientX - touchUp.clientX,
      y: touchDown.clientY - touchUp.clientY
    }

    // We're only tracking left/right swiping.
    if (Math.abs(diff.x) > Math.abs(diff.y)) {
      if (diff.x > 0) this.next();
      else this.prev();
    }

    this.touchDown = null;
  },

  eachSlide: function(callback) {
    [].forEach.call(this.children, callback);
  }
});
<|endoftext|>


<commit_before>// @flow

import React, { Component, Children, cloneElement, type ReactElement } from 'react';
import { View, Animated, StyleSheet, ScrollView, Dimensions } from 'react-native';
import AnimatedOverlay from 'react-native-animated-overlay';
import _ from 'lodash';

import Separator from './Separator';
import Animation from './Animation';

const { width: WIDTH, height: HEIGHT } = Dimensions.get('window');

// action sheet states
const ACTION_SHEET_OPENING: string = 'opening';
const ACTION_SHEET_OPENED: string = 'opened';
const ACTION_SHEET_CLOSING: string = 'closing';
const ACTION_SHEET_CLOSED: string = 'closed';

const DEFAULT_ANIMATION_DURATION: number = 250;

const INITIAL_TOP_POSITION: number = -180;
const INITIAL_BOTTOM_POSITION: number = HEIGHT * -1;

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    top: 0,
    left: 0,
    backgroundColor: 'white',
  },
  contentContainer: {
    width: WIDTH,
    position: 'absolute',
    backgroundColor: 'white',
  },
  scrollView: {
  },
  hidden: {
    top: -10000,
    left: 0,
    height: 0,
    width: 0,
  },
});

type Props = {
  onShow?: () => void;
  onHide?: () => void;
  show?: boolean;
  animationDuration?: number;
  overlayOpacity?: number;
  position?: 'top' | 'bottom';
  onChange?: () => void;
  multiple?: boolean;
  showSparator?: boolean;
  value?: any;
  defaultValue?: any;
  hideOnSelceted?: boolean;
  children?: any;
};

const defaultProps = {
  onShow: () => {},
  onHide: () => {},
  show: false,
  animationDuration: DEFAULT_ANIMATION_DURATION,
  overlayOpacity: 0.3,
  position: 'top',
  onChange: () => {},
  multiple: false,
  showSparator: true,
  value: null,
  defaultValue: null,
  hideOnSelceted: true,
  children: null,
};

class ActionSheet extends Component {
  props: Props

  static defaultProps = defaultProps

  constructor(props: Props) {
    super(props);

    let initValue = (props.value || props.defaultValue);
    initValue = Array.isArray(initValue)
      ? initValue
      : (initValue === null && []) || [initValue];

    this.state = {
      show: props.show,
      selectedData: initValue,
      actionSheetState: ACTION_SHEET_CLOSED,
      actionSheetAnimation: new Animation(this.hideActionSheetPosition),
    };
  }

  componentDidMount() {
    if (this.props.show) {
      this.show();
    }
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.position !== nextProps.position) {
      this.setState({ actionSheetAnimation: new Animation(this.hideActionSheetPosition) });
    }

    if (this.props.show !== nextProps.show) {
      if (nextProps.show) {
        this.show();
      } else {
        this.hide();
      }
    }

    if (!_.isEqual(this.props.value, nextProps.value)) {
      const selectedData = [];
      nextProps.value.forEach((value) => {
        if (!this.props.multiple && selectedData.length !== 0) {
          return;
        }
        selectedData.push(value);
      });
      this.setState({ selectedData });
    }
  }

  get showActionSheetPosition(): string {
    const { position } = this.props;
    if (position === 'top') {
      return INITIAL_TOP_POSITION * -1;
    }
    return 0;
  }

  get hideActionSheetPosition(): string {
    const { position } = this.props;
    if (position === 'top') {
      return INITIAL_TOP_POSITION;
    }
    return INITIAL_BOTTOM_POSITION * -1;
  }

  onOverlayPress = (): void => {
    this.hide();
  }

  setActionSheetState(toValue: number, callback?: Function = () => {}): void {
    const { animationDuration } = this.props;
    const isClosed = (this.state.actionSheetState === ACTION_SHEET_CLOSED);

    let actionSheetState = isClosed ? ACTION_SHEET_OPENING : ACTION_SHEET_CLOSING;

    this.setState({ actionSheetState });

    this.state.actionSheetAnimation.toValue(toValue, animationDuration, () => {
      const isClosing = (this.state.actionSheetState === ACTION_SHEET_CLOSING);
      actionSheetState = isClosing ? ACTION_SHEET_CLOSED : ACTION_SHEET_OPENED;

      this.setState({ actionSheetState });
      callback();
    });
  }

  show = (callback?: Function = () => {}): void => {
    if ([ACTION_SHEET_OPENING, ACTION_SHEET_OPENED].includes(this.state.actionSheetState)) {
      return;
    }

    const { onShow } = this.props;

    this.setState({ show: true });
    this.setActionSheetState(this.showActionSheetPosition);
    onShow();
    callback();
  }

  hide = (callback?: Function = () => {}): void => {
    if ([ACTION_SHEET_CLOSING, ACTION_SHEET_CLOSED].includes(this.state.actionSheetState)) {
      return;
    }

    const { onHide } = this.props;

    this.setState({ show: false });
    this.setActionSheetState(this.hideActionSheetPosition);
    onHide();
    callback();
  }

  onItemPress(value, index): void {
    const { hideOnSelceted } = this.props;
    if (hideOnSelceted) {
      // this.hide();
    }

    if (Object.values(this.state.selectedData).includes(value)) {
      this.unselectItem(value, index);
      return;
    }

    this.selectItem(value, index);
  }

  selectItem(value, index) {
    const { multiple: isMultiSelect, onChange } = this.props;
    let selectedData = [];

    if (isMultiSelect) {
      selectedData = [...this.state.selectedData];
    }

    selectedData.push(value);
    this.setState({ selectedData });
    onChange(value, index, selectedData);
  }

  unselectItem(value, index) {
    const { multiple: isMultiSelect, onChange } = this.props;
    let selectedData = [];

    if (isMultiSelect) {
      selectedData = [...this.state.selectedData];
      selectedData.splice(index, 1);
    }

    this.setState({ selectedData });
    onChange(value, index, selectedData);
  }

  isItemSelected(index): boolean {
    return !!this.state.selectedData[index];
  }

  renderItems(): ReactElement {
    const { children, showSparator } = this.props;
    const separator = showSparator ? <Separator /> : null;

    return Children.map(children, (child) => {
      const index = this.state.selectedData.indexOf(child.value);
      const item = cloneElement(child, {
        index,
        selected: this.state.selectedData.includes(child.props.value),
        onPress: (selectedValue, selectedIndex) => {
          child.props.onPress(selectedValue, selectedIndex);
          this.onItemPress(selectedValue, selectedIndex);
        },
      });

      return (
        <View style={{ flex: 1 }}>
          {item}
          {separator}
        </View>
      );
    });
  }

  render() {
    const { animationDuration, overlayOpacity, position } = this.props;
    const { actionSheetState, actionSheetAnimation: { animations } } = this.state;

    const overlayShow = [ACTION_SHEET_OPENED, ACTION_SHEET_OPENING].includes(actionSheetState);
    const pointerEvents = (actionSheetState === ACTION_SHEET_OPENED) ? 'auto' : 'none';
    const hidden = actionSheetState === ACTION_SHEET_CLOSED && styles.hidden;

    const contentPosition = (position === 'top')
      ? { top: INITIAL_TOP_POSITION }
      : { bottom: INITIAL_BOTTOM_POSITION };

    const scrollView = (position === 'top')
      ? { paddingTop: 30 }
      : null;

    return (
      <View style={[styles.container, hidden]}>
        <AnimatedOverlay
          onPress={this.onOverlayPress}
          overlayShow={overlayShow}
          duration={animationDuration}
          opacity={overlayOpacity}
          pointerEvents={pointerEvents}
        />
        <Animated.View
          style={[styles.contentContainer, contentPosition, animations]}
        >
          <ScrollView style={[styles.scrollView, scrollView]}>
            {this.renderItems()}
          </ScrollView>
        </Animated.View>
      </View>
    );
  }
}

export default ActionSheet;
<commit_msg>uncomment this line<commit_after>// @flow

import React, { Component, Children, cloneElement, type ReactElement } from 'react';
import { View, Animated, StyleSheet, ScrollView, Dimensions } from 'react-native';
import AnimatedOverlay from 'react-native-animated-overlay';
import _ from 'lodash';

import Separator from './Separator';
import Animation from './Animation';

const { width: WIDTH, height: HEIGHT } = Dimensions.get('window');

// action sheet states
const ACTION_SHEET_OPENING: string = 'opening';
const ACTION_SHEET_OPENED: string = 'opened';
const ACTION_SHEET_CLOSING: string = 'closing';
const ACTION_SHEET_CLOSED: string = 'closed';

const DEFAULT_ANIMATION_DURATION: number = 250;

const INITIAL_TOP_POSITION: number = -180;
const INITIAL_BOTTOM_POSITION: number = HEIGHT * -1;

const styles = StyleSheet.create({
  container: {
    position: 'absolute',
    top: 0,
    left: 0,
    backgroundColor: 'white',
  },
  contentContainer: {
    width: WIDTH,
    position: 'absolute',
    backgroundColor: 'white',
  },
  scrollView: {
  },
  hidden: {
    top: -10000,
    left: 0,
    height: 0,
    width: 0,
  },
});

type Props = {
  onShow?: () => void;
  onHide?: () => void;
  show?: boolean;
  animationDuration?: number;
  overlayOpacity?: number;
  position?: 'top' | 'bottom';
  onChange?: () => void;
  multiple?: boolean;
  showSparator?: boolean;
  value?: any;
  defaultValue?: any;
  hideOnSelceted?: boolean;
  children?: any;
};

const defaultProps = {
  onShow: () => {},
  onHide: () => {},
  show: false,
  animationDuration: DEFAULT_ANIMATION_DURATION,
  overlayOpacity: 0.3,
  position: 'top',
  onChange: () => {},
  multiple: false,
  showSparator: true,
  value: null,
  defaultValue: null,
  hideOnSelceted: true,
  children: null,
};

class ActionSheet extends Component {
  props: Props

  static defaultProps = defaultProps

  constructor(props: Props) {
    super(props);

    let initValue = (props.value || props.defaultValue);
    initValue = Array.isArray(initValue)
      ? initValue
      : (initValue === null && []) || [initValue];

    this.state = {
      show: props.show,
      selectedData: initValue,
      actionSheetState: ACTION_SHEET_CLOSED,
      actionSheetAnimation: new Animation(this.hideActionSheetPosition),
    };
  }

  componentDidMount() {
    if (this.props.show) {
      this.show();
    }
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.position !== nextProps.position) {
      this.setState({ actionSheetAnimation: new Animation(this.hideActionSheetPosition) });
    }

    if (this.props.show !== nextProps.show) {
      if (nextProps.show) {
        this.show();
      } else {
        this.hide();
      }
    }

    if (!_.isEqual(this.props.value, nextProps.value)) {
      const selectedData = [];
      nextProps.value.forEach((value) => {
        if (!this.props.multiple && selectedData.length !== 0) {
          return;
        }
        selectedData.push(value);
      });
      this.setState({ selectedData });
    }
  }

  get showActionSheetPosition(): string {
    const { position } = this.props;
    if (position === 'top') {
      return INITIAL_TOP_POSITION * -1;
    }
    return 0;
  }

  get hideActionSheetPosition(): string {
    const { position } = this.props;
    if (position === 'top') {
      return INITIAL_TOP_POSITION;
    }
    return INITIAL_BOTTOM_POSITION * -1;
  }

  onOverlayPress = (): void => {
    this.hide();
  }

  setActionSheetState(toValue: number, callback?: Function = () => {}): void {
    const { animationDuration } = this.props;
    const isClosed = (this.state.actionSheetState === ACTION_SHEET_CLOSED);

    let actionSheetState = isClosed ? ACTION_SHEET_OPENING : ACTION_SHEET_CLOSING;

    this.setState({ actionSheetState });

    this.state.actionSheetAnimation.toValue(toValue, animationDuration, () => {
      const isClosing = (this.state.actionSheetState === ACTION_SHEET_CLOSING);
      actionSheetState = isClosing ? ACTION_SHEET_CLOSED : ACTION_SHEET_OPENED;

      this.setState({ actionSheetState });
      callback();
    });
  }

  show = (callback?: Function = () => {}): void => {
    if ([ACTION_SHEET_OPENING, ACTION_SHEET_OPENED].includes(this.state.actionSheetState)) {
      return;
    }

    const { onShow } = this.props;

    this.setState({ show: true });
    this.setActionSheetState(this.showActionSheetPosition);
    onShow();
    callback();
  }

  hide = (callback?: Function = () => {}): void => {
    if ([ACTION_SHEET_CLOSING, ACTION_SHEET_CLOSED].includes(this.state.actionSheetState)) {
      return;
    }

    const { onHide } = this.props;

    this.setState({ show: false });
    this.setActionSheetState(this.hideActionSheetPosition);
    onHide();
    callback();
  }

  onItemPress(value, index): void {
    const { hideOnSelceted } = this.props;
    if (hideOnSelceted) {
      this.hide();
    }

    if (Object.values(this.state.selectedData).includes(value)) {
      this.unselectItem(value, index);
      return;
    }

    this.selectItem(value, index);
  }

  selectItem(value, index) {
    const { multiple: isMultiSelect, onChange } = this.props;
    let selectedData = [];

    if (isMultiSelect) {
      selectedData = [...this.state.selectedData];
    }

    selectedData.push(value);
    this.setState({ selectedData });
    onChange(value, index, selectedData);
  }

  unselectItem(value, index) {
    const { multiple: isMultiSelect, onChange } = this.props;
    let selectedData = [];

    if (isMultiSelect) {
      selectedData = [...this.state.selectedData];
      selectedData.splice(index, 1);
    }

    this.setState({ selectedData });
    onChange(value, index, selectedData);
  }

  isItemSelected(index): boolean {
    return !!this.state.selectedData[index];
  }

  renderItems(): ReactElement {
    const { children, showSparator } = this.props;
    const separator = showSparator ? <Separator /> : null;

    return Children.map(children, (child) => {
      const index = this.state.selectedData.indexOf(child.value);
      const item = cloneElement(child, {
        index,
        selected: this.state.selectedData.includes(child.props.value),
        onPress: (selectedValue, selectedIndex) => {
          child.props.onPress(selectedValue, selectedIndex);
          this.onItemPress(selectedValue, selectedIndex);
        },
      });

      return (
        <View style={{ flex: 1 }}>
          {item}
          {separator}
        </View>
      );
    });
  }

  render() {
    const { animationDuration, overlayOpacity, position } = this.props;
    const { actionSheetState, actionSheetAnimation: { animations } } = this.state;

    const overlayShow = [ACTION_SHEET_OPENED, ACTION_SHEET_OPENING].includes(actionSheetState);
    const pointerEvents = (actionSheetState === ACTION_SHEET_OPENED) ? 'auto' : 'none';
    const hidden = actionSheetState === ACTION_SHEET_CLOSED && styles.hidden;

    const contentPosition = (position === 'top')
      ? { top: INITIAL_TOP_POSITION }
      : { bottom: INITIAL_BOTTOM_POSITION };

    const scrollView = (position === 'top')
      ? { paddingTop: 30 }
      : null;

    return (
      <View style={[styles.container, hidden]}>
        <AnimatedOverlay
          onPress={this.onOverlayPress}
          overlayShow={overlayShow}
          duration={animationDuration}
          opacity={overlayOpacity}
          pointerEvents={pointerEvents}
        />
        <Animated.View
          style={[styles.contentContainer, contentPosition, animations]}
        >
          <ScrollView style={[styles.scrollView, scrollView]}>
            {this.renderItems()}
          </ScrollView>
        </Animated.View>
      </View>
    );
  }
}

export default ActionSheet;
<|endoftext|>


<commit_before>//shorthands claims namespaces
var fm = {
  'nameIdentifier': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier',
  'email': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
  'name': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name',
  'givenname': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname',
  'surname': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname',
  'upn': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn',
  'groups': 'http://schemas.xmlsoap.org/claims/Group'
};

/**
 *
 * Passport User Profile Mapper
 *
 * A class to map passport.js user profile to a wsfed claims based identity.
 *
 * Passport Profile:
 * http://passportjs.org/guide/profile/
 *
 * Claim Types:
 * http://msdn.microsoft.com/en-us/library/microsoft.identitymodel.claims.claimtypes_members.aspx
 *
 * @param  {Object} pu Passport.js user profile
 */
function PassportProfileMapper (pu) {
  if(!(this instanceof PassportProfileMapper)) {
    return new PassportProfileMapper(pu);
  }
  this._pu = pu;
}

/**
 * map passport.js user profile to a wsfed claims based identity.
 *
 * @return {Object}    WsFederation claim identity
 */
PassportProfileMapper.prototype.getClaims = function () {
  var claims = {};

  claims[fm.nameIdentifier]  = this._pu.id;
  claims[fm.email]      = this._pu.emails[0] && this._pu.emails[0].value;
  claims[fm.name]       = this._pu.displayName;
  claims[fm.givenname]  = this._pu.name.givenName;
  claims[fm.surname]    = this._pu.name.familyName;

  var dontRemapAttributes = ['emails', 'displayName', 'name', 'id', '_json'];

  Object.keys(this._pu).filter(function (k) {
      return !~dontRemapAttributes.indexOf(k);
    }).forEach(function (k) {
      claims['http://schemas.passportjs.com/' + k] = this._pu[k];
    }.bind(this));

  return claims;
};

/**
 * returns the nameidentifier for the saml token.
 *
 * @return {Object} object containing a nameIdentifier property and optional nameIdentifierFormat.
 */
PassportProfileMapper.prototype.getNameIdentifier = function () {
  var claims = this.getClaims();

  return {
    nameIdentifier: claims[fm.nameIdentifier] ||
                    claims[fm.name] ||
                    claims[fm.emailaddress]
  };

};

/**
 * claims metadata used in the metadata endpoint.
 *
 * @param  {Object} pu Passport.js profile
 * @return {[type]}    WsFederation claim identity
 */
PassportProfileMapper.prototype.metadata = [ {
  id: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
  optional: true,
  displayName: 'E-Mail Address',
  description: 'The e-mail address of the user'
}, {
  id: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
  optional: true,
  displayName: 'Given Name',
  description: 'The given name of the user'
}, {
  id: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
  optional: true,
  displayName: 'Name',
  description: 'The unique name of the user'
}, {
  id: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
  optional: true,
  displayName: 'Surname',
  description: 'The surname of the user'
}, {
  id: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
  optional: true,
  displayName: 'Name ID',
  description: 'The SAML name identifier of the user'
}];

module.exports = PassportProfileMapper;<commit_msg>don't map givenname and surname if the profile doesn't have name<commit_after>//shorthands claims namespaces
var fm = {
  'nameIdentifier': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier',
  'email': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress',
  'name': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name',
  'givenname': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname',
  'surname': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname',
  'upn': 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn',
  'groups': 'http://schemas.xmlsoap.org/claims/Group'
};

/**
 *
 * Passport User Profile Mapper
 *
 * A class to map passport.js user profile to a wsfed claims based identity.
 *
 * Passport Profile:
 * http://passportjs.org/guide/profile/
 *
 * Claim Types:
 * http://msdn.microsoft.com/en-us/library/microsoft.identitymodel.claims.claimtypes_members.aspx
 *
 * @param  {Object} pu Passport.js user profile
 */
function PassportProfileMapper (pu) {
  if(!(this instanceof PassportProfileMapper)) {
    return new PassportProfileMapper(pu);
  }
  this._pu = pu;
}

/**
 * map passport.js user profile to a wsfed claims based identity.
 *
 * @return {Object}    WsFederation claim identity
 */
PassportProfileMapper.prototype.getClaims = function () {
  var claims = {};

  claims[fm.nameIdentifier]  = this._pu.id;
  claims[fm.email]      = this._pu.emails[0] && this._pu.emails[0].value;
  claims[fm.name]       = this._pu.displayName;

  if (this._pu.name) {
    claims[fm.givenname]  = this._pu.name.givenName;
    claims[fm.surname]    = this._pu.name.familyName;
  }

  var dontRemapAttributes = ['emails', 'displayName', 'name', 'id', '_json'];

  Object.keys(this._pu).filter(function (k) {
      return !~dontRemapAttributes.indexOf(k);
    }).forEach(function (k) {
      claims['http://schemas.passportjs.com/' + k] = this._pu[k];
    }.bind(this));

  return claims;
};

/**
 * returns the nameidentifier for the saml token.
 *
 * @return {Object} object containing a nameIdentifier property and optional nameIdentifierFormat.
 */
PassportProfileMapper.prototype.getNameIdentifier = function () {
  var claims = this.getClaims();

  return {
    nameIdentifier: claims[fm.nameIdentifier] ||
                    claims[fm.name] ||
                    claims[fm.emailaddress]
  };

};

/**
 * claims metadata used in the metadata endpoint.
 *
 * @param  {Object} pu Passport.js profile
 * @return {[type]}    WsFederation claim identity
 */
PassportProfileMapper.prototype.metadata = [ {
  id: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
  optional: true,
  displayName: 'E-Mail Address',
  description: 'The e-mail address of the user'
}, {
  id: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname",
  optional: true,
  displayName: 'Given Name',
  description: 'The given name of the user'
}, {
  id: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
  optional: true,
  displayName: 'Name',
  description: 'The unique name of the user'
}, {
  id: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname",
  optional: true,
  displayName: 'Surname',
  description: 'The surname of the user'
}, {
  id: "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
  optional: true,
  displayName: 'Name ID',
  description: 'The SAML name identifier of the user'
}];

module.exports = PassportProfileMapper;<|endoftext|>


<commit_before>import React from 'react';

import Link from 'gatsby-link';

import Anchor from '../../ui/Anchor';
import CodeBlock from '../../ui/CodeBlock';
import DocPage from '../../containers/DocPage';
import ApiDocs from '../../containers/ApiDocs';

export default () => (
  <DocPage title="DayPickerInput API">
    <CodeBlock
    >{`import DayPickerInput from 'react-day-picker/DayPickerInput'`}</CodeBlock>

API summary

Component’s Props

      classNames,{' '}
      clickUnselectsDay,{' '}
      component,{' '}
      dayPickerProps, format,{' '}
      formatDate, keepFocus,{' '}
      hideOnDayClick,{' '}
      inputProps,{' '}
      overlayComponent,{' '}
      parseDate, placeholder,{' '}
      showOverlay, value

Event handlers

      onDayChange

Public methods

      getDayPicker, getInput,{' '}
      hideDayPicker,{' '}
      showDayPicker

    <ApiDocs>

DayPickerInput Props

        <Anchor id="classNames" />
        classNames Object

Customize the CSS class names used when rendering the component.

The object expects the following keys:

      <CodeBlock>{`{
  container,            // The container element
  overlayWrapper,       // The overlay's wrapper
  overlay,              // The overlay's container
}`}</CodeBlock>

        <Anchor id="clickUnselectsDay" />
        clickUnselectsDay boolean = false

        Unselect and clear the input when clicking on a previously selected day.

        <Anchor id="component" />
        component string | React.Component = "input"

The component class to render the input field.

        The component must be compatible with the standard HTML{' '}
        input: i.e. it should support the
        onChange, onFocus, onKeyUp,{' '}
        onClick and onBlur props, and the{' '}
        focus method.

        If your custom component doesn’t support such props, wrap it in a
        component contaning them. For example:

      <CodeBlock>{`import React from 'react';
import { DayPickerInput } from 'react-day-picker';
import MyInputWithoutFocus from './MyInputWithoutFocus';

class MyInputWithFocus extends React.Component {
  focus = () => {
    this.input.focus();
  }
  render() {
    return (
      <MyInputWithoutFocus
        ref={el => (this.input = el)}
        {...this.props}
      />
    );
  }
}

function MyDayPickerInput(props) {
  return <DayPickerInput component={MyInputWithFocus} />
}
`}</CodeBlock>

        <Anchor id="dayPickerProps" />
        dayPickerProps Object

        The <Link to="/api/DayPicker">DayPicker props</Link> to customize the
        calendar rendered in the overlay.

        <Anchor id="format" />
        format string | string[]

        The format string(s) used for formatting and parsing dates. It works
        with{' '}

          parseDate
        {' '}
        and{' '}

          formatDate

        <Anchor id="formatDate" />
        formatDate{' '}

          (date: Date?, format: string? | string[]?, locale: string?) ⇒ string

        Date formatter used for displaying the selected date as value of the
        input field. As default, it returns dates formatted as{' '}
        YYYY-M-D.

        Arguments: format is the value coming from the{' '}

          format
        {' '}
        prop, while locale is from{' '}

          dayPickerProps
        .

        See also{' '}

          parseDate
        .

        If you are using moment.js in your
        app, we already provide this function as addon: see{' '}
        <Link to="/examples/input-moment">this example</Link>.

        <Anchor id="hideOnDayClick" />
        hideOnDayClick boolean = true

Hide the overlay when the user clicks on a day cell.

        <Anchor id="inputProps" />
        inputProps Object

        Additional props to add to the input component. The{' '}
        value key is ignored: use the{' '}

          value
        {' '}
        prop instead.

        <Anchor id="keepFocus" />
        keepFocus boolean = true

        Keep focus on the input field after switching the focus into the
        overlay. You may want to disable the focus on the input field when using
        an overlayComponent.

        <Anchor id="overlayComponent" />
        overlayComponent React.Component

        A custom React Element or Component to use for the overlay. The element
        will receive the following props:

          selectedDay: ?Date The currently selected day

          month: Date The month displayed in the calendar

          input: DOM Element The input field

          classNames: Object The input field

          ...props: Object Other props to pass to the HTML element
          to handle interaction with the calendar

      <CodeBlock>
        {`import React from 'react';
import { DayPickerInput } from 'react-day-picker';

function OverlayComponent({ children, ...props }) {
  return (

My custom things

      /* include the calendar */
      { children }

Some content below the calendar

  );
}

function MyDayPickerInput() {
  return <DayPickerInput overlayComponent={OverlayComponent} />;
}`}
      </CodeBlock>

        As default, the input field keep always the focus when interacting with
        the calendar. However this may cause problems if the custom overlay has
        an input field, so you may need to set{' '}
        {`keepFocus={false}`}. See{' '}
        <Link to="/examples/input-custom-overlay">this example</Link>.

        <Anchor id="parseDate" />
        parseDate{' '}

          (str: string?, format: string? | string[]?, locale: string?) ⇒ Date |
          void

        Date parser used for parsing the string typed in the input field. As
        default, it parses only dates formatted as YYYY-M-D.

        Arguments: format is the value coming from the{' '}

          format
        {' '}
        prop, while locale is from{' '}

          dayPickerProps
        .
See also{' '}

          formatDate
        .

        If you are using moment.js in your
        app, we already provide this function as addon: see{' '}
        <Link to="/examples/input-moment">this example</Link>.

        <Anchor id="placeholder" />
        placeholder string

        The placeholder to use for the input field.

        <Anchor id="showOverlay" />
        showOverlay boolean = false

        Show the overlay during the initial rendering of the component. This is
        useful if you want to keep the overlay visibile while styling it.

        <Anchor id="value" />
        value string | Date

        The value of the input field.

Event handlers

        <Anchor id="onDayChange" />
        onDayChange (day: ?Date, modifiers: Object) ⇒ void

        Handler function called when the user types a valid day – according to
        the{' '}

          format
        {' '}
        prop – or when a day is clicked on the calendar. If the typed value is
        empty or not valid, `day` is undefined and `modifiers` is
        an empty object.

Public methods

        <Anchor id="getDayPicker" />
        getDayPicker () ⇒ DayPicker

Return the DayPicker instance.

        <Anchor id="getInput" />
        getInput () ⇒ DOMNode | ReactNode

Return the input element instance.

        <Anchor id="showDayPicker" />
        showDayPicker () ⇒ void

Show the Day Picker overlay.

        <Anchor id="hideDayPicker" />
        hideDayPicker () ⇒ void

Hide the Day Picker overlay.

    </ApiDocs>
  </DocPage>
);
<commit_msg>Update docs for #747, #742<commit_after>import React from 'react';

import Link from 'gatsby-link';

import Anchor from '../../ui/Anchor';
import CodeBlock from '../../ui/CodeBlock';
import DocPage from '../../containers/DocPage';
import ApiDocs from '../../containers/ApiDocs';

export default () => (
  <DocPage title="DayPickerInput API">
    <CodeBlock
    >{`import DayPickerInput from 'react-day-picker/DayPickerInput'`}</CodeBlock>

API summary

Component’s Props

      classNames,{' '}
      clickUnselectsDay,{' '}
      component,{' '}
      dayPickerProps, format,{' '}
      formatDate, keepFocus,{' '}
      hideOnDayClick,{' '}
      inputProps,{' '}
      overlayComponent,{' '}
      parseDate, placeholder,{' '}
      showOverlay, value

Event handlers

      onDayChange

Public methods

      getDayPicker, getInput,{' '}
      hideDayPicker,{' '}
      showDayPicker

    <ApiDocs>

DayPickerInput Props

        <Anchor id="classNames" />
        classNames Object

Customize the CSS class names used when rendering the component.

The object expects the following keys:

      <CodeBlock>{`{
  container,            // The container element
  overlayWrapper,       // The overlay's wrapper
  overlay,              // The overlay's container
}`}</CodeBlock>

        <Anchor id="clickUnselectsDay" />
        clickUnselectsDay boolean = false

        Unselect and clear the input when clicking on a previously selected day.

        <Anchor id="component" />
        component string | React.Component = "input"

The component class to render the input field.

      <CodeBlock
      >{`<DayPickerInput component={props => <input {...props} />} />`}</CodeBlock>

        The component must support the
        onChange, onFocus, onKeyUp,{' '}
        onClick and onBlur props. If you want to keep
        the focus when the user picks a day, the component class must have a{' '}
        focus method.

        <Anchor id="dayPickerProps" />
        dayPickerProps Object

        The <Link to="/api/DayPicker">DayPicker props</Link> to customize the
        calendar rendered in the overlay.

        <Anchor id="format" />
        format string | string[]

        The format string(s) used for formatting and parsing dates. It works
        with{' '}

          parseDate
        {' '}
        and{' '}

          formatDate

        <Anchor id="formatDate" />
        formatDate{' '}

          (date: Date?, format: string? | string[]?, locale: string?) ⇒ string

        Date formatter used for displaying the selected date as value of the
        input field. As default, it returns dates formatted as{' '}
        YYYY-M-D.

        Arguments: format is the value coming from the{' '}

          format
        {' '}
        prop, while locale is from{' '}

          dayPickerProps
        .

        See also{' '}

          parseDate
        .

        If you are using moment.js in your
        app, we already provide this function as addon: see{' '}
        <Link to="/examples/input-moment">this example</Link>.

        <Anchor id="hideOnDayClick" />
        hideOnDayClick boolean = true

Hide the overlay when the user clicks on a day cell.

        <Anchor id="inputProps" />
        inputProps Object

        Additional props to add to the input component. The{' '}
        value key is ignored: use the{' '}

          value
        {' '}
        prop instead.

        <Anchor id="keepFocus" />
        keepFocus boolean = true

        Keep focus on the input field after switching the focus into the
        overlay. You may want to disable the focus on the input field when using
        an overlayComponent.

        <Anchor id="overlayComponent" />
        overlayComponent React.Component

        A custom React Element or Component to use for the overlay. The element
        will receive the following props:

          selectedDay: ?Date The currently selected day

          month: Date The month displayed in the calendar

          input: DOM Element The input field

          classNames: Object The input field

          ...props: Object Other props to pass to the HTML element
          to handle interaction with the calendar

      <CodeBlock>
        {`import React from 'react';
import { DayPickerInput } from 'react-day-picker';

function OverlayComponent({ children, ...props }) {
  return (

My custom things

      /* include the calendar */
      { children }

Some content below the calendar

  );
}

function MyDayPickerInput() {
  return <DayPickerInput overlayComponent={OverlayComponent} />;
}`}
      </CodeBlock>

        As default, the input field keep always the focus when interacting with
        the calendar. However this may cause problems if the custom overlay has
        an input field, so you may need to set{' '}
        {`keepFocus={false}`}. See{' '}
        <Link to="/examples/input-custom-overlay">this example</Link>.

        <Anchor id="parseDate" />
        parseDate{' '}

          (str: string?, format: string? | string[]?, locale: string?) ⇒ Date |
          void

        Date parser used for parsing the string typed in the input field. As
        default, it parses only dates formatted as YYYY-M-D.

        Arguments: format is the value coming from the{' '}

          format
        {' '}
        prop, while locale is from{' '}

          dayPickerProps
        .
See also{' '}

          formatDate
        .

        If you are using moment.js in your
        app, we already provide this function as addon: see{' '}
        <Link to="/examples/input-moment">this example</Link>.

        <Anchor id="placeholder" />
        placeholder string

        The placeholder to use for the input field.

        <Anchor id="showOverlay" />
        showOverlay boolean = false

        Show the overlay during the initial rendering of the component. This is
        useful if you want to keep the overlay visibile while styling it.

        <Anchor id="value" />
        value string | Date

        The value of the input field.

Event handlers

        <Anchor id="onDayChange" />
        onDayChange (day: ?Date, modifiers: Object) ⇒ void

        Handler function called when the user types a valid day – according to
        the{' '}

          format
        {' '}
        prop – or when a day is clicked on the calendar. If the typed value is
        empty or not valid, `day` is undefined and `modifiers` is
        an empty object.

Public methods

        <Anchor id="getDayPicker" />
        getDayPicker () ⇒ DayPicker

Return the DayPicker instance.

        <Anchor id="getInput" />
        getInput () ⇒ DOMNode | ReactNode

Return the input element instance.

        <Anchor id="showDayPicker" />
        showDayPicker () ⇒ void

Show the Day Picker overlay.

        <Anchor id="hideDayPicker" />
        hideDayPicker () ⇒ void

Hide the Day Picker overlay.

    </ApiDocs>
  </DocPage>
);
<|endoftext|>