text:
require 'test_helper'

class EmployeeLocationTest < ActiveSupport::TestCase
  # test "the truth" do
  #   assert true
  # end
end


text:
import os
from unittest import mock
import urllib

from absl import flags
from absl.testing import absltest
import tensorflow as tf
import lzma  # pylint: disable=g-bad-import-order

from tensorflow_federated.python.simulation.datasets import download

FLAGS = flags.FLAGS

class DownloadTest(absltest.TestCase):

  @mock.patch.object(tf.io.gfile, 'exists', side_effect=[True, False])
  @mock.patch.object(tf.io.gfile, 'makedirs')
  def test_uncache_file_is_fetched_with_content_length(self, mock_makedirs,
                                                       mock_exists):
    test_data = b'data'
    test_url = 'http://www.test.org/my/test/file.lzma'
    mock_urlopen = mock.mock_open(read_data=lzma.compress(test_data))
    mock_urlopen.return_value.headers = {'context-length': str(len(test_data))}
    with mock.patch.object(urllib.request, 'urlopen', mock_urlopen):
      path = download.get_compressed_file(test_url, cache_dir=FLAGS.test_tmpdir)
    expected_output_path = os.path.join(FLAGS.test_tmpdir, 'file')
    self.assertEqual(path, expected_output_path)
    mock_exists.assert_has_calls(
        [mock.call(FLAGS.test_tmpdir),
         mock.call(expected_output_path)])
    mock_urlopen.assert_called_once_with(test_url)
    mock_makedirs.assert_not_called()
    self.assertTrue(os.path.exists(expected_output_path))
    with open(expected_output_path, 'rb') as test_file:
      self.assertEqual(test_file.read(), test_data)

  @mock.patch.object(tf.io.gfile, 'exists', side_effect=[True, False])
  @mock.patch.object(tf.io.gfile, 'makedirs')
  def test_uncache_file_is_fetched_without_content_length(
      self, mock_makedirs, mock_exists):
    test_data = b'data'
    test_url = 'http://www.test.org/my/test/file.lzma'
    mock_urlopen = mock.mock_open(read_data=lzma.compress(test_data))
    # Do not add content-length headers, ensuring that the python code
    # doesn't error if the HTTP header was missing.
    mock_urlopen.return_value.headers = {}
    with mock.patch.object(urllib.request, 'urlopen', mock_urlopen):
      path = download.get_compressed_file(test_url, cache_dir=FLAGS.test_tmpdir)
    expected_output_path = os.path.join(FLAGS.test_tmpdir, 'file')
    self.assertEqual(path, expected_output_path)
    mock_exists.assert_has_calls(
        [mock.call(FLAGS.test_tmpdir),
         mock.call(expected_output_path)])
    mock_urlopen.assert_called_once_with(test_url)
    mock_makedirs.assert_not_called()
    self.assertTrue(os.path.exists(expected_output_path))
    with open(expected_output_path, 'rb') as test_file:
      self.assertEqual(test_file.read(), test_data)

  @mock.patch.object(tf.io.gfile, 'exists', return_value=True)
  @mock.patch.object(tf.io.gfile, 'makedirs')
  def test_cached_file_is_not_fetched(self, mock_makedirs, mock_exists):
    mock_urlopen = mock.mock_open(read_data=lzma.compress(b'test'))
    mock_urlopen.return_value.headers = {}
    with mock.patch.object(urllib.request, 'urlopen', mock_urlopen):
      download.get_compressed_file(
          'http://www.test.org/my/test/file.lzma', cache_dir=FLAGS.test_tmpdir)
    mock_exists.assert_has_calls([
        mock.call(FLAGS.test_tmpdir),
        mock.call(os.path.join(FLAGS.test_tmpdir, 'file'))
    ])
    mock_makedirs.assert_not_called()
    mock_urlopen.assert_not_called()

  def test_non_lzma_extension_errors(self):
    with self.assertRaises(ValueError):
      download.get_compressed_file('http://www.test.org/my/test/file.bz2')

  @mock.patch.object(tf.io.gfile, 'exists', side_effect=[False, True])
  @mock.patch.object(tf.io.gfile, 'makedirs')
  def test_cache_dir_not_exists_creates_dirs(self, mock_makedirs, mock_exists):
    cache_subdir = os.path.join(FLAGS.test_tmpdir, 'test_subdir')
    download.get_compressed_file('http://www.test.org/my/test/file.lzma',
                                 cache_subdir)
    mock_makedirs.assert_called_once_with(cache_subdir)
    mock_exists.assert_has_calls([
        mock.call(cache_subdir),
        mock.call(os.path.join(cache_subdir, 'file')),
    ])

if __name__ == '__main__':
  absltest.main()

redpajama_set_name: RedPajamaGithub


text:
//------------------------------------------------------------------------------
// <autogenerated>
//     This code was generated by a CodeSmith Template.
//
//     DO NOT MODIFY contents of this file. Changes to this
//     file will be lost if the code is regenerated.
// </autogenerated>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;

namespace Ugly.Data.Entities
{
    public partial class Department
    {
        public Department()
        {
            EmployeeDepartments = new HashSet<EmployeeDepartment>();
        }

        public int DepartmentId { get; set; }
        public Byte[] Name { get; set; }
        public Byte[] Description { get; set; }
        public int CreatedBy { get; set; }
        public int UpdatedBy { get; set; }

        public virtual Employees CreatedByEmployees { get; set; }
        public virtual Employees UpdatedByEmployees { get; set; }
        public virtual ICollection<EmployeeDepartment> EmployeeDepartments { get; set; }
    }
}


text:
// Copyright 2015-2016 Google Inc. All Rights Reserved.
// Licensed under the Apache License Version 2.0.

using System;

namespace Google.PowerShell.Provider
{
    /// <summary>
    /// A CacheItem will get an object from the given update function and continue to return that object for
    /// the duration of cacheLifetime. It will then make another call to the update function to get a new
    /// version of the object. The default cache lifetime is one minute.
    /// </summary>
    public class CacheItem<T>
    {
        private static TimeSpan s_minuteTimeSpan = TimeSpan.FromMinutes(1);
        private DateTimeOffset _lastUpdate = DateTimeOffset.MinValue;
        private readonly TimeSpan _cacheLifetime;
        private T _value;
        private readonly Func<T> _update;

        /// <summary>
        /// Get the value after applying the default update function
        /// if the value is out of date.
        /// </summary>
        public T Value
        {
            get
            {
                return GetValueWithUpdateFunction(_update);
            }
        }

        /// <summary>
        /// Returns true if the cache is out of date.
        /// </summary>
        public bool CacheOutOfDate()
        {
            return DateTimeOffset.Now > _lastUpdate + _cacheLifetime;
        }

        /// <summary>
        /// Get the value after applying an update function to the value
        /// if the value is out of date.
        /// </summary>
        /// <param name="updateFunc">The update function that is used to update _value.</param>
        /// <returns>Returns the updated value.</returns>
        public T GetValueWithUpdateFunction(Func<T> updateFunc)
        {
            if (CacheOutOfDate() && updateFunc != null)
            {
                _value = updateFunc();
                _lastUpdate = DateTimeOffset.Now;
            }
            return _value;
        }

        /// <summary>
        /// Get the last stored value without calling the update function.
        /// </summary>
        public T GetLastValueWithoutUpdate()
        {
            return _value;
        }

        /// <summary>
        /// Initialize a CacheItem with a cache reset time set to cacheLifetime
        /// and update function set to update.
        /// </summary>
        /// <param name="update">
        /// Update function that is used to update the value if cache is out of date.
        /// Default to null, which means GetValueWithUpdateFunction, GetLastValueWithoutUpdate
        /// and Value will return default value for type T.
        /// </param>
        /// <param name="cacheLifetime">Time span that the cache is valid for. Default to 1 minute.</param>
        public CacheItem(Func<T> update = null, TimeSpan? cacheLifetime = null)
        {
            _update = update;
            _cacheLifetime = cacheLifetime ?? s_minuteTimeSpan;
        }
    }
}


text:
package com.rasterfoundry.api.user

import com.rasterfoundry.datamodel.User

import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpMethods._
import akka.http.scaladsl.model._
import akka.http.scaladsl.model.headers.{Authorization, GenericHttpCredentials}
import akka.http.scaladsl.unmarshalling.Unmarshal
import com.rasterfoundry.api.utils.{
  Auth0Exception,
  Config,
  ManagementBearerToken
}
import com.github.blemale.scaffeine.{AsyncLoadingCache, Scaffeine}
import com.typesafe.scalalogging.LazyLogging
import de.heikoseeberger.akkahttpcirce.ErrorAccumulatingCirceSupport._
import io.circe._
import io.circe.generic.JsonCodec
import io.circe.syntax._

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scala.concurrent.duration._

@JsonCodec
final case class Auth0User(
    email: Option[String],
    email_verified: Option[Boolean],
    username: Option[String],
    phone_number: Option[String],
    phone_verified: Option[String],
    user_id: Option[String],
    created_at: Option[String],
    updated_at: Option[String],
    identities: Option[Json],
    // app_metadata: Option[Json],
    user_metadata: Option[Json],
    picture: Option[String],
    name: Option[String],
    nickname: Option[String],
    // multifactor: Option[Seq[String]],
    // last_ip: Option[String],
    // last_login: Option[String],
    // logins_count: Option[Int],
    // blocked: Option[Boolean],
    given_name: Option[String],
    family_name: Option[String]
)

@JsonCodec
final case class UserWithOAuth(
    user: User,
    oauth: Auth0User
)

object UserWithOAuth {
  implicit val encodeUser: Encoder[User] = Encoder.forProduct8(
    "id",
    "name",
    "email",
    "profileImageUri",
    "emailNotifications",
    "visibility",
    "dropboxCredential",
    "planetCredential"
  )(
    u =>
      (u.id,
       u.name,
       u.email,
       u.profileImageUri,
       u.emailNotifications,
       u.visibility,
       u.dropboxCredential,
       u.planetCredential))
}
@JsonCodec
final case class Auth0UserUpdate(
    email: Option[String],
    phone_number: Option[String],
    user_metadata: Option[Json],
    username: Option[String]
)

@JsonCodec
final case class UserWithOAuthUpdate(
    user: User.Create,
    oauth: Auth0UserUpdate
)
object Auth0UserService extends Config with LazyLogging {

  import com.rasterfoundry.api.AkkaSystem._

  val uri = Uri(s"https://$auth0Domain/api/v2/device-credentials")
  val userUri = Uri(s"https://$auth0Domain/api/v2/users")
  val auth0BearerHeader = List(
    Authorization(GenericHttpCredentials("Bearer", auth0Bearer))
  )

  val authBearerTokenCache: AsyncLoadingCache[Int, ManagementBearerToken] =
    Scaffeine()
      .expireAfterWrite(1.hour)
      .maximumSize(1)
      .buildAsyncFuture((_: Int) => getManagementBearerToken())

  def getManagementBearerToken(): Future[ManagementBearerToken] = {
    val bearerTokenUri = Uri(s"https://$auth0Domain/oauth/token")

    val params = FormData(
      "client_id" -> auth0ManagementClientId,
      "client_secret" -> auth0ManagementSecret,
      "audience" -> s"https://$auth0Domain/api/v2/",
      "grant_type" -> "client_credentials"
    ).toEntity

    Http()
      .singleRequest(
        HttpRequest(
          method = POST,
          uri = bearerTokenUri,
          entity = params
        ))
      .flatMap {
        case HttpResponse(StatusCodes.OK, _, entity, _) =>
          Unmarshal(entity).to[ManagementBearerToken]
        case HttpResponse(errCode, _, error, _) =>
          throw new Auth0Exception(errCode, error.toString)
      }
  }

  def requestAuth0User(
      userId: String,
      bearerToken: ManagementBearerToken): Future[Auth0User] = {
    val auth0UserBearerHeader = List(
      Authorization(GenericHttpCredentials("Bearer", bearerToken.access_token))
    )
    Http()
      .singleRequest(
        HttpRequest(
          method = GET,
          uri = s"$userUri/${userId}",
          headers = auth0UserBearerHeader
        ))
      .flatMap {
        case HttpResponse(StatusCodes.OK, _, entity, _) =>
          Unmarshal(entity).to[Auth0User]
        case HttpResponse(StatusCodes.Unauthorized, _, error, _) =>
          if (error.toString.contains("invalid_refresh_token")) {
            throw new IllegalArgumentException("Refresh token not recognized")
          } else {
            throw new Auth0Exception(StatusCodes.Unauthorized, error.toString)
          }
        case HttpResponse(errCode, _, error, _) =>
          logger.info(s"error $error")
          throw new Auth0Exception(errCode, error.toString)
      }
  }

  def updateAuth0User(userId: String,
                      auth0UserUpdate: Auth0UserUpdate): Future[Auth0User] = {
    for {
      bearerToken <- authBearerTokenCache.get(1)
      auth0User <- requestAuth0UserUpdate(userId, auth0UserUpdate, bearerToken)
    } yield auth0User
  }

  def requestAuth0UserUpdate(
      userId: String,
      auth0UserUpdate: Auth0UserUpdate,
      bearerToken: ManagementBearerToken): Future[Auth0User] = {
    val auth0UserBearerHeader = List(
      Authorization(GenericHttpCredentials("Bearer", bearerToken.access_token))
    )
    Http()
      .singleRequest(
        HttpRequest(
          method = PATCH,
          uri = s"$userUri/${userId}",
          headers = auth0UserBearerHeader,
          entity = HttpEntity(
            ContentTypes.`application/json`,
            auth0UserUpdate.asJson.noSpaces
          )
        ))
      .flatMap {
        case HttpResponse(StatusCodes.OK, _, entity, _) =>
          Unmarshal(entity).to[Auth0User]
        case HttpResponse(StatusCodes.ClientError(400), _, _, _) =>
          throw new IllegalArgumentException(
            "Request must specify a valid field to update")
        case HttpResponse(StatusCodes.Unauthorized, _, error, _) =>
          if (error.toString.contains("invalid_refresh_token")) {
            throw new IllegalArgumentException("Refresh token not recognized")
          } else {
            throw new Auth0Exception(StatusCodes.Unauthorized, error.toString)
          }
        case HttpResponse(errCode, _, error, _) =>
          logger.info(s"error $error")
          throw new Auth0Exception(errCode, error.toString)
      }
  }
}


text:
AJAX with the SlimUI Framework

The SlimUI framework includes a service called FrameworkAJAX which can be used to make AJAX requests to REST services.

var successCallback = function(response){
    // Save the response to your model
    // Modelbuilder({data: response.data});
};

var errorCallback = function(){
    console.log('Error fetching data in FetchJSONService');
};

var request = {
    url: url,
    method: 'GET',  // Optionally 'POST'
    data: {} // Not required for GET, but required for 'POST'
};

FrameworkAJAX.sendRequest( request, successCallback, errorCallback);

Please look at \sample_application\Examples\Services\Services\FetchJSONService.js for details.


text:
import { computed } from '@ember/object';
import Beat from './beat';
import Sampler from './sampler';

const beatBank = new WeakMap();

/**
 * An instance of this class has a single "sound" (comprised of one or multiple
 * audio sources) but provides methods to play that sound repeatedly, mixed with
 * "rests," in a rhythmic way. An instance of this class behaves very similarly
 * to a "lane" on a drum machine.
 *
 * @public
 * @class BeatTrack
 * @extends Sampler
 *
 * @todo need a way to stop a BeatTrack once it's started. Maybe by creating
 * the times in advance and not calling play until it's the next beat in the
 * queue?
 */
const BeatTrack = Sampler.extend({

  /**
   * Determines the number of beats in a BeatTrack instance.
   *
   * @public
   * @property numBeats
   * @type {number}
   */
  numBeats: 4,

  /**
   * If specified, Determines length of time, in milliseconds, before isPlaying
   * and currentTimeIsPlaying are automatically switched back to false after
   * having been switched to true for each beat. 100ms is used by default.
   *
   * @public
   * @property duration
   * @type {number}
   * @default 100
   */
  duration: 100,

  /**
   * Computed property. An array of Beat instances. The number of Beat instances
   * in the array is always the same as the `numBeats` property. If 'numBeats'
   * or duration changes. This property will be recomputed, but any beats that
   * previously existed are reused so that they will maintain their `active`
   * state.
   *
   * @public
   * @property beats
   * @type {array|Beat}
   */
  beats: computed('numBeats', 'duration', function() {
    let beats = [];
    let numBeats = this.get('numBeats');
    let existingBeats;

    if (beatBank.has(this)) {
      existingBeats = beatBank.get(this);
      numBeats = numBeats - existingBeats.length;
    }

    for (let i = 0; i < numBeats; i++) {
      const beat = Beat.create({
        duration: this.get('duration'),
        _parentPlayIn: this.playIn.bind(this),
        _parentPlay: this.play.bind(this)
      });

      beats.push(beat);
    }

    if (existingBeats) {
      beats = existingBeats.concat(beats);
    }

    beatBank.set(this, beats);

    return beats;
  }),

  /**
   * Calls play on all Beat instances in the beats array.
   *
   * @public
   * @method playBeats
   *
   * @param {number} bpm The tempo at which the beats should be played.
   *
   * @param noteType {number} The (rhythmic) length of each beat. Fractions
   * are suggested here so that it's easy to reason about. For example, for
   * eighth notes, pass in `1/8`.
   */
  playBeats(bpm, noteType) {
    this._callPlayMethodOnBeats('playIn', bpm, noteType);
  },

  /**
   * Calls play on `active` Beat instances in the beats array. Any beat that
   * is not marked active is effectively a "rest".
   *
   * @public
   * @method playActiveBeats
   *
   * @param {number} bpm The tempo at which the beats and rests should be played.
   *
   * @param noteType {number} The (rhythmic) length of each beat/rest. Fractions
   * are suggested here so that it's easy to reason about. For example, for
   * eighth notes, pass in `1/8`.
   */
  playActiveBeats(bpm, noteType) {
    this._callPlayMethodOnBeats('ifActivePlayIn', bpm, noteType);
  },

  /**
   * The underlying method behind playBeats and playActiveBeats.
   *
   * @private
   * @method _callPlayMethodOnBeats
   *
   * @param {string} method The method that should be called on each beat.
   *
   * @param {number} bpm The tempo that should be used to calculate the length
   * of a beat/rest.
   *
   * @param noteType {number} The (rhythmic) length of each beat/rest that should
   * be used to calculate the length of a beat/rest in seconds.
   */
  _callPlayMethodOnBeats(method, bpm, noteType=1 / 4) {
    // http://bradthemad.org/guitar/tempo_explanation.php
    const duration = (240 * noteType) / bpm;
    this.get('beats').map((beat, idx) => beat[method](idx * duration));
  }
});

export default BeatTrack;


text:
require 'spec_helper'
require 'rack'
require 'rack/builder'
require 'rack/mock'
require 'rollbar/middleware/rack/builder'

describe Rollbar::Middleware::Rack::Builder, :reconfigure_notifier => true do
  class RackMockError < Exception; end

  let(:action) do
    proc { fail(RackMockError, 'the-error') }
  end

  let(:app) do
    action_proc = action

    Rack::Builder.new { run action_proc }
  end

  let(:request) do
    Rack::MockRequest.new(app)
  end

  let(:exception) { kind_of(RackMockError) }
  let(:uncaught_level) { Rollbar.configuration.uncaught_exception_level }

  it 'reports the error to Rollbar' do
    expect(Rollbar).to receive(:log).with(uncaught_level, exception)
    expect { request.get('/will_crash') }.to raise_error(exception)
  end

  context 'with GET parameters' do
    let(:params) do
      { 'key' => 'value' }
    end

    it 'sends them to Rollbar' do
      expect do
        request.get('/will_crash', :params => params)
      end.to raise_error(exception)

      expect(Rollbar.last_report[:request][:params]).to be_eql(params)
    end
  end

  context 'with POST parameters' do
    let(:params) do
      { 'key' => 'value' }
    end

    it 'sends them to Rollbar' do
      expect do
        request.post('/will_crash', :input => params.to_json, 'CONTENT_TYPE' => 'application/json')
      end.to raise_error(exception)

      expect(Rollbar.last_report[:request][:params]).to be_eql(params)
    end
  end

  context 'with array POST parameters' do
    let(:params) do
      [{ :key => 'value'}, 'string', 10]
    end

    it 'sends a body.multi key in params' do
      expect do
        request.post('/will_crash', :input => params.to_json, 'CONTENT_TYPE' => 'application/json')
      end.to raise_error(exception)

      reported_params = Rollbar.last_report[:request][:params]
      expect(reported_params['body.multi']).to be_eql([{'key' => 'value'}, 'string', 10])
    end
  end

  context 'with not array or hash POST parameters' do
    let(:params) { 1000 }

    it 'sends a body.multi key in params' do
      expect do
        request.post('/will_crash', :input => params.to_json, 'CONTENT_TYPE' => 'application/json')
      end.to raise_error(exception)

      reported_params = Rollbar.last_report[:request][:params]
      expect(reported_params['body.value']).to be_eql(1000)
    end
  end

  context 'with multiple HTTP_X_FORWARDED_PROTO values' do
    let(:headers) do
      { 'HTTP_X_FORWARDED_PROTO' => 'https,http' }
    end

    it 'uses the first scheme to generate the url' do
      expect do
        request.post('/will_crash', headers)
      end.to raise_error(exception)

      last_report = Rollbar.last_report
      expect(last_report[:request][:url]).to match(/https:/)
    end
  end

  context 'without HTTP_X_FORWARDED_PROTO' do
    it 'uses the the url_scheme set by Rack' do
      expect do
        request.post('/will_crash')
      end.to raise_error(exception)

      last_report = Rollbar.last_report
      expect(last_report[:request][:url]).to match(/http:/)
    end
  end

  context 'with single HTTP_X_FORWARDED_PROTO value' do
    let(:headers) do
      { 'HTTP_X_FORWARDED_PROTO' => 'https' }
    end

    it 'uses the scheme received in X-Forwarded-Proto header' do
      expect do
        request.post('/will_crash', headers)
      end.to raise_error(exception)

      last_report = Rollbar.last_report
      expect(last_report[:request][:url]).to match(/https:/)
    end
  end
end


text:
var FARKY_FRIENDS = {

    nameBox : null,
    noteBox : null,
    colorPicker : null,
    groupPicker : null,
    colorChoice : null,
    sampleText : null,
    sampleUser : null,
    sampleNote : null,
    usermode : null,
    modifymode : null,
    oldname : null,

    init : function() {
	try {
		var defaultname;

		FARKY.init();
		//FARKY_DATA.init();

		// Locate static page elements
		FARKY_FRIENDS.nameBox = document.getElementById("nameBox");
		FARKY_FRIENDS.noteBox = document.getElementById("noteBox");
		FARKY_FRIENDS.groupPicker = document.getElementById("groupPicker");
		FARKY_FRIENDS.colorPicker = document.getElementById("colorPicker");
		FARKY_FRIENDS.colorChoice = document.getElementById("colorChoice");
		FARKY_FRIENDS.sampleUser  = document.getElementById("sampleUser");
		FARKY_FRIENDS.sampleNote  = document.getElementById("sampleNote");
		FARKY_FRIENDS.sampleText  = document.getElementById("sampleText");

		FARKY_COLORPICKER_CUSTOMIZE(FARKY_FRIENDS.colorPicker, document);

		// Determine if this is an add or modify command, and if we're doing a user or a group.
		switch (window.arguments[0]) {
			case "add": 	FARKY_FRIENDS.modifymode = false; break;
			case "modify":	FARKY_FRIENDS.modifymode = true;  break;
			default:	throw("Bad add/modify arg '" + window.arguments[0] + "' in window options.");
		}

		switch (window.arguments[1]) {
			case "user":	FARKY_FRIENDS.usermode = true;  break;
			case "group":	FARKY_FRIENDS.usermode = false; break;
			default:	throw("Bad user/group arg '" + window.arguments[1] + 	"' in window options.");
		}

		defaultname = window.arguments[2];
		if (defaultname == undefined) defaultname = "";
		FARKY_FRIENDS.oldname = defaultname;

		// Setup window title and "ok" button.
		var dowhat = "";
		if (FARKY_FRIENDS.modifymode) { dowhat = "Edit "; } else { dowhat = "Add ";   }
		if (FARKY_FRIENDS.usermode)   { dowhat += "user";   } else { dowhat += "group"; }

		//document.documentElement.setAttribute("title", "Farky Friends - " + dowhat);
		document.title = "Farky Friends - " + dowhat;

		// Label the textfield properly
		var nametype = document.getElementById("nametype");
		if (FARKY_FRIENDS.usermode) { nametype.value = "User name:"; } else { nametype.value = "Group name:"; }

		// Initialize the list of group names. If editing a group, hide the unneeded selector.
		if (FARKY_FRIENDS.usermode) {
			var selectedIndex = 0;
			var menuitem = null;
			var groupMenu = document.getElementById("groupMenu");

			// Temporarily remove "Individual Color" entry. [This is a bit hackish, but having a
			// default entry probably helps the default widget box size render right.]
			var customColor = groupMenu.firstChild;
			groupMenu.removeChild(customColor);

			// Create menuitems for each friend group.
			var i = 0, sortedGroups = new Array();
			for (var group in FARKY_DATA.groups) { sortedGroups[i++] = group; }
			sortedGroups.sort();

			for (i = 0; i < sortedGroups.length; i++) {
				menuitem = document.createElement("menuitem");
				groupMenu.appendChild(menuitem);
				menuitem.label = sortedGroups[i];
				menuitem.value = FARKY_DATA.groups[sortedGroups[i]].color;
				if (FARKY_FRIENDS.modifymode && sortedGroups[i] == FARKY_DATA.friends[defaultname].group) {
					selectedIndex = i;
				}
			}

			// If user is a individual color, set index to where Individual Color entry will be.
			// Otherwise hide the colorpicker stuff until user selects Individual Color from menu.
			if (FARKY_FRIENDS.modifymode && FARKY_DATA.friends[defaultname].group == "") {
				selectedIndex = sortedGroups.length;
				FARKY_FRIENDS.colorPicker.color = FARKY_DATA.friends[defaultname].color;
			} else if (menuitem) {
				FARKY_FRIENDS.colorChoice.style.visibility = "hidden";
			}

			// Reattach "Individual Color" entry at the end.
			groupMenu.appendChild(customColor);

			// Select the appropriate menu item.
			FARKY_FRIENDS.groupPicker.selectedIndex = selectedIndex;

			if (FARKY_FRIENDS.modifymode) {
				FARKY_FRIENDS.noteBox.value = FARKY_DATA.friends[defaultname].note;
			}
		} else {
			document.getElementById("groupChoice").hidden = true;
			document.getElementById("noteRow").hidden = true;
			if (defaultname != "") { FARKY_FRIENDS.colorPicker.color = FARKY_DATA.groups[defaultname].color; }
		}

		// Set the group/user name if provided.
		FARKY_FRIENDS.nameBox.value = defaultname;

		// disable editing username in modify mode. ticket #4
		if (FARKY_FRIENDS.modifymode && FARKY_FRIENDS.usermode) {
			FARKY_FRIENDS.nameBox.disabled = true;
		}

		FARKY_FRIENDS.update_sampleTextUser();
		FARKY_FRIENDS.update_sampleTextNote();
		FARKY_FRIENDS.update_sampleTextColor();

	} catch (e) {
		alert("Farky: Failed to initialize Friends window: " + e);
	}
    },

    save : function() {
	  try {
		var color, newname, group, note;

		newname = FARKY_FRIENDS.nameBox.value;
		note    = FARKY_FRIENDS.noteBox.value;

		// Trim leading/trailing whitespace
		newname = newname.replace(/^\s+/,'').replace(/\s+$/,'');
		note    = note.replace(/^\s+/,'').replace(/\s+$/,'');

		// Check for empty input
		if (newname == "") {
			alert("You must enter a name.");
			return false;
		}

		// Check for special values used internally...
		if (!FARKY_FRIENDS.usermode && (
			newname == "Individual Color..." ||
			newname == "Individual Color" ||
			newname == "All Friends" ||
			newname.charAt(0) == '#')) {

			alert("Error: This is an invalid group name. Bad kitty!");
			return false;
		}

		// Check to see if the new (or modified) name already exists
		if (!FARKY_FRIENDS.modifymode || FARKY_FRIENDS.oldname != newname) {
			if (FARKY_FRIENDS.usermode && FARKY_DATA.friends[newname] || !FARKY_FRIENDS.usermode && FARKY_DATA.groups[newname]) {
				alert("Error: The name you have entered already exists.");
				return false;
			}
		}

		// Determine what color (anad perhaps group) was selected
		if (FARKY_FRIENDS.colorChoice.style.visibility == "hidden") {
			color = FARKY_FRIENDS.groupPicker.value;
			group = FARKY_FRIENDS.groupPicker.label;
		} else {
			color = FARKY_FRIENDS.colorPicker.color;
			group = "";
		}

		// If we're modifying and entry, remove the current entry first.
		if (FARKY_FRIENDS.modifymode) {
			if (FARKY_FRIENDS.usermode) {
				delete FARKY_DATA.friends[FARKY_FRIENDS.oldname];
			} else {
				var f;

				// If group name or color changed, update all users
				if (newname != FARKY_FRIENDS.oldname || FARKY_DATA.groups[FARKY_FRIENDS.oldname].color != color) {
					for (f in FARKY_DATA.friends) {
						if (FARKY_DATA.friends[f].group == FARKY_FRIENDS.oldname) {
							FARKY_DATA.friends[f].group = newname;
							FARKY_DATA.friends[f].color = color;
						}
					}
				}

				delete FARKY_DATA.groups[FARKY_FRIENDS.oldname];
			}
		}

		if (FARKY_FRIENDS.usermode) {
			FARKY_DATA.friends[newname] = new Array();
			FARKY_DATA.friends[newname].color = color;
			FARKY_DATA.friends[newname].group = group;
			FARKY_DATA.friends[newname].note  = note;
		} else {
			FARKY_DATA.groups[newname] = new Array();
			FARKY_DATA.groups[newname].color = color;
		}

		FARKY_DATA.save_friends();

		return true;

	} catch (e) {
		alert("Farky: Failed to save Friend Data: " + e);
		return false;
	}
    },

    update_sampleTextColor : function() {
	// If the color picker is hidden, use the color from the group selector instead.
	if (FARKY_FRIENDS.colorChoice.style.visibility == "hidden") {
		FARKY_FRIENDS.sampleText.style.backgroundColor = FARKY_FRIENDS.groupPicker.value;
	} else {
		FARKY_FRIENDS.sampleText.style.backgroundColor = FARKY_FRIENDS.colorPicker.color;
	}
    },

    update_sampleTextUser : function() {

	if (!FARKY_FRIENDS.usermode) return;

	if (FARKY_FRIENDS.nameBox.value == "") {
		FARKY_FRIENDS.sampleUser.value = "Some Guy";
	} else {
		FARKY_FRIENDS.sampleUser.value = FARKY_FRIENDS.nameBox.value;
	}
    },

    update_sampleTextNote : function() {

	if (!FARKY_FRIENDS.usermode) return;

	FARKY_FRIENDS.sampleNote.value = FARKY_FRIENDS.noteBox.value;
    }
};


text:
#include "postgres.h"

#include "access/htup_details.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "miscadmin.h"
#include "storage/sinval.h"
#include "storage/smgr.h"
#include "utils/catcache.h"
#include "utils/inval.h"
#include "utils/memdebug.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/relmapper.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"

/*
 * To minimize palloc traffic, we keep pending requests in successively-
 * larger chunks (a slightly more sophisticated version of an expansible
 * array).  All request types can be stored as SharedInvalidationMessage
 * records.  The ordering of requests within a list is never significant.
 */
typedef struct InvalidationChunk
{
	struct InvalidationChunk *next;		/* list link */
	int			nitems;			/* # items currently stored in chunk */
	int			maxitems;		/* size of allocated array in this chunk */
	SharedInvalidationMessage msgs[FLEXIBLE_ARRAY_MEMBER];
} InvalidationChunk;

typedef struct InvalidationListHeader
{
	InvalidationChunk *cclist;	/* list of chunks holding catcache msgs */
	InvalidationChunk *rclist;	/* list of chunks holding relcache msgs */
} InvalidationListHeader;

/*----------------
 * Invalidation info is divided into two lists:
 *	1) events so far in current command, not yet reflected to caches.
 *	2) events in previous commands of current transaction; these have
 *	   been reflected to local caches, and must be either broadcast to
 *	   other backends or rolled back from local cache when we commit
 *	   or abort the transaction.
 * Actually, we need two such lists for each level of nested transaction,
 * so that we can discard events from an aborted subtransaction.  When
 * a subtransaction commits, we append its lists to the parent's lists.
 *
 * The relcache-file-invalidated flag can just be a simple boolean,
 * since we only act on it at transaction commit; we don't care which
 * command of the transaction set it.
 *----------------
 */

typedef struct TransInvalidationInfo
{
	/* Back link to parent transaction's info */
	struct TransInvalidationInfo *parent;

	/* Subtransaction nesting depth */
	int			my_level;

	/* head of current-command event list */
	InvalidationListHeader CurrentCmdInvalidMsgs;

	/* head of previous-commands event list */
	InvalidationListHeader PriorCmdInvalidMsgs;

	/* init file must be invalidated? */
	bool		RelcacheInitFileInval;
} TransInvalidationInfo;

thread_local static TransInvalidationInfo *transInvalInfo = NULL;

thread_local static SharedInvalidationMessage *SharedInvalidMessagesArray;
thread_local static int	numSharedInvalidMessagesArray;
thread_local static int	maxSharedInvalidMessagesArray;

/*
 * Dynamically-registered callback functions.  Current implementation
 * assumes there won't be very many of these at once; could improve if needed.
 */

#define MAX_SYSCACHE_CALLBACKS 32
#define MAX_RELCACHE_CALLBACKS 10

thread_local static struct SYSCACHECALLBACK
{
	int16		id;				/* cache number */
	SyscacheCallbackFunction function;
	Datum		arg;
}	syscache_callback_list[MAX_SYSCACHE_CALLBACKS];

thread_local static int	syscache_callback_count = 0;

thread_local static struct RELCACHECALLBACK
{
	RelcacheCallbackFunction function;
	Datum		arg;
}	relcache_callback_list[MAX_RELCACHE_CALLBACKS];

thread_local static int	relcache_callback_count = 0;

/* ----------------------------------------------------------------
 *				Invalidation list support functions
 *
 * These three routines encapsulate processing of the "chunked"
 * representation of what is logically just a list of messages.
 * ----------------------------------------------------------------
 */

/*
 * AddInvalidationMessage
 *		Add an invalidation message to a list (of chunks).
 *
 * Note that we do not pay any great attention to maintaining the original
 * ordering of the messages.
 */
static void
AddInvalidationMessage(InvalidationChunk **listHdr,
					   SharedInvalidationMessage *msg)
{
	InvalidationChunk *chunk = *listHdr;

	if (chunk == NULL)
	{
		/* First time through; create initial chunk */
#define FIRSTCHUNKSIZE 32
		chunk = (InvalidationChunk *)
			MemoryContextAlloc(CurTransactionContext,
							   offsetof(InvalidationChunk, msgs) +
					FIRSTCHUNKSIZE * sizeof(SharedInvalidationMessage));
		chunk->nitems = 0;
		chunk->maxitems = FIRSTCHUNKSIZE;
		chunk->next = *listHdr;
		*listHdr = chunk;
	}
	else if (chunk->nitems >= chunk->maxitems)
	{
		/* Need another chunk; double size of last chunk */
		int			chunksize = 2 * chunk->maxitems;

		chunk = (InvalidationChunk *)
			MemoryContextAlloc(CurTransactionContext,
							   offsetof(InvalidationChunk, msgs) +
						 chunksize * sizeof(SharedInvalidationMessage));
		chunk->nitems = 0;
		chunk->maxitems = chunksize;
		chunk->next = *listHdr;
		*listHdr = chunk;
	}
	/* Okay, add message to current chunk */
	chunk->msgs[chunk->nitems] = *msg;
	chunk->nitems++;
}

/*
 * Append one list of invalidation message chunks to another, resetting
 * the source chunk-list pointer to NULL.
 */
static void
AppendInvalidationMessageList(InvalidationChunk **destHdr,
							  InvalidationChunk **srcHdr)
{
	InvalidationChunk *chunk = *srcHdr;

	if (chunk == NULL)
		return;					/* nothing to do */

	while (chunk->next != NULL)
		chunk = chunk->next;

	chunk->next = *destHdr;

	*destHdr = *srcHdr;

	*srcHdr = NULL;
}

/*
 * Process a list of invalidation messages.
 *
 * This is a macro that executes the given code fragment for each message in
 * a message chunk list.  The fragment should refer to the message as *msg.
 */
#define ProcessMessageList(listHdr, codeFragment) \
	do { \
		InvalidationChunk *_chunk; \
		for (_chunk = (listHdr); _chunk != NULL; _chunk = _chunk->next) \
		{ \
			int		_cindex; \
			for (_cindex = 0; _cindex < _chunk->nitems; _cindex++) \
			{ \
				SharedInvalidationMessage *msg = &_chunk->msgs[_cindex]; \
				codeFragment; \
			} \
		} \
	} while (0)

/*
 * Process a list of invalidation messages group-wise.
 *
 * As above, but the code fragment can handle an array of messages.
 * The fragment should refer to the messages as msgs[], with n entries.
 */
#define ProcessMessageListMulti(listHdr, codeFragment) \
	do { \
		InvalidationChunk *_chunk; \
		for (_chunk = (listHdr); _chunk != NULL; _chunk = _chunk->next) \
		{ \
			SharedInvalidationMessage *msgs = _chunk->msgs; \
			int		n = _chunk->nitems; \
			codeFragment; \
		} \
	} while (0)

/* ----------------------------------------------------------------
 *				Invalidation set support functions
 *
 * These routines understand about the division of a logical invalidation
 * list into separate physical lists for catcache and relcache entries.
 * ----------------------------------------------------------------
 */

/*
 * Add a catcache inval entry
 */
static void
AddCatcacheInvalidationMessage(InvalidationListHeader *hdr,
							   int id, uint32 hashValue, Oid dbId)
{
	SharedInvalidationMessage msg;

	Assert(id < CHAR_MAX);
	msg.cc.id = (int8) id;
	msg.cc.dbId = dbId;
	msg.cc.hashValue = hashValue;
	/*
	 * Define padding bytes in SharedInvalidationMessage structs to be
	 * defined. Otherwise the sinvaladt.c ringbuffer, which is accessed by
	 * multiple processes, will cause spurious valgrind warnings about
	 * undefined memory being used. That's because valgrind remembers the
	 * undefined bytes from the last local process's store, not realizing that
	 * another process has written since, filling the previously uninitialized
	 * bytes
	 */
	VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));

	AddInvalidationMessage(&hdr->cclist, &msg);
}

/*
 * Add a whole-catalog inval entry
 */
static void
AddCatalogInvalidationMessage(InvalidationListHeader *hdr,
							  Oid dbId, Oid catId)
{
	SharedInvalidationMessage msg;

	msg.cat.id = SHAREDINVALCATALOG_ID;
	msg.cat.dbId = dbId;
	msg.cat.catId = catId;
	/* check AddCatcacheInvalidationMessage() for an explanation */
	VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));

	AddInvalidationMessage(&hdr->cclist, &msg);
}

/*
 * Add a relcache inval entry
 */
static void
AddRelcacheInvalidationMessage(InvalidationListHeader *hdr,
							   Oid dbId, Oid relId)
{
	SharedInvalidationMessage msg;

	/* Don't add a duplicate item */
	/* We assume dbId need not be checked because it will never change */
	ProcessMessageList(hdr->rclist,
					   if (msg->rc.id == SHAREDINVALRELCACHE_ID &&
						   msg->rc.relId == relId)
					   return);

	/* OK, add the item */
	msg.rc.id = SHAREDINVALRELCACHE_ID;
	msg.rc.dbId = dbId;
	msg.rc.relId = relId;
	/* check AddCatcacheInvalidationMessage() for an explanation */
	VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));

	AddInvalidationMessage(&hdr->rclist, &msg);
}

/*
 * Add a snapshot inval entry
 */
static void
AddSnapshotInvalidationMessage(InvalidationListHeader *hdr,
							   Oid dbId, Oid relId)
{
	SharedInvalidationMessage msg;

	/* Don't add a duplicate item */
	/* We assume dbId need not be checked because it will never change */
	ProcessMessageList(hdr->rclist,
					   if (msg->sn.id == SHAREDINVALSNAPSHOT_ID &&
						   msg->sn.relId == relId)
					   return);

	/* OK, add the item */
	msg.sn.id = SHAREDINVALSNAPSHOT_ID;
	msg.sn.dbId = dbId;
	msg.sn.relId = relId;
	/* check AddCatcacheInvalidationMessage() for an explanation */
	VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));

	AddInvalidationMessage(&hdr->rclist, &msg);
}

/*
 * Append one list of invalidation messages to another, resetting
 * the source list to empty.
 */
static void
AppendInvalidationMessages(InvalidationListHeader *dest,
						   InvalidationListHeader *src)
{
	AppendInvalidationMessageList(&dest->cclist, &src->cclist);
	AppendInvalidationMessageList(&dest->rclist, &src->rclist);
}

/*
 * Execute the given function for all the messages in an invalidation list.
 * The list is not altered.
 *
 * catcache entries are processed first, for reasons mentioned above.
 */
static void
ProcessInvalidationMessages(InvalidationListHeader *hdr,
							void (*func) (SharedInvalidationMessage *msg))
{
	ProcessMessageList(hdr->cclist, func(msg));
	ProcessMessageList(hdr->rclist, func(msg));
}

/*
 * As above, but the function is able to process an array of messages
 * rather than just one at a time.
 */
static void
ProcessInvalidationMessagesMulti(InvalidationListHeader *hdr,
				 void (*func) (const SharedInvalidationMessage *msgs, int n))
{
	ProcessMessageListMulti(hdr->cclist, func(msgs, n));
	ProcessMessageListMulti(hdr->rclist, func(msgs, n));
}

/* ----------------------------------------------------------------
 *					  private___ support functions
 * ----------------------------------------------------------------
 */

/*
 * RegisterCatcacheInvalidation
 *
 * Register an invalidation event for a catcache tuple entry.
 */
static void
RegisterCatcacheInvalidation(int cacheId,
							 uint32 hashValue,
							 Oid dbId)
{
	AddCatcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
								   cacheId, hashValue, dbId);
}

/*
 * RegisterCatalogInvalidation
 *
 * Register an invalidation event for all catcache entries from a catalog.
 */
static void
RegisterCatalogInvalidation(Oid dbId, Oid catId)
{
	AddCatalogInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
								  dbId, catId);
}

/*
 * RegisterRelcacheInvalidation
 *
 * As above, but register a relcache invalidation event.
 */
static void
RegisterRelcacheInvalidation(Oid dbId, Oid relId)
{
	AddRelcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
								   dbId, relId);

	/*
	 * Most of the time, relcache invalidation is associated with system
	 * catalog updates, but there are a few cases where it isn't.  Quick hack
	 * to ensure that the next CommandCounterIncrement() will think that we
	 * need to do CommandEndInvalidationMessages().
	 */
	(void) GetCurrentCommandId(true);

	/*
	 * If the relation being invalidated is one of those cached in the
	 * relcache init file, mark that we need to zap that file at commit.
	 */
	if (RelationIdIsInInitFile(relId))
		transInvalInfo->RelcacheInitFileInval = true;
}

/*
 * RegisterSnapshotInvalidation
 *
 * Register an invalidation event for MVCC scans against a given catalog.
 * Only needed for catalogs that don't have catcaches.
 */
static void
RegisterSnapshotInvalidation(Oid dbId, Oid relId)
{
	AddSnapshotInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs,
								   dbId, relId);
}

/*
 * LocalExecuteInvalidationMessage
 *
 * Process a single invalidation message (which could be of any type).
 * Only the local caches are flushed; this does not transmit the message
 * to other backends.
 */
void
LocalExecuteInvalidationMessage(SharedInvalidationMessage *msg)
{
	if (msg->id >= 0)
	{
		if (msg->cc.dbId == MyDatabaseId || msg->cc.dbId == InvalidOid)
		{
			InvalidateCatalogSnapshot();

			CatalogCacheIdInvalidate(msg->cc.id, msg->cc.hashValue);

			CallSyscacheCallbacks(msg->cc.id, msg->cc.hashValue);
		}
	}
	else if (msg->id == SHAREDINVALCATALOG_ID)
	{
		if (msg->cat.dbId == MyDatabaseId || msg->cat.dbId == InvalidOid)
		{
			InvalidateCatalogSnapshot();

			CatalogCacheFlushCatalog(msg->cat.catId);

			/* CatalogCacheFlushCatalog calls CallSyscacheCallbacks as needed */
		}
	}
	else if (msg->id == SHAREDINVALRELCACHE_ID)
	{
		if (msg->rc.dbId == MyDatabaseId || msg->rc.dbId == InvalidOid)
		{
			int			i;

			RelationCacheInvalidateEntry(msg->rc.relId);

			for (i = 0; i < relcache_callback_count; i++)
			{
				struct RELCACHECALLBACK *ccitem = relcache_callback_list + i;

				(*ccitem->function) (ccitem->arg, msg->rc.relId);
			}
		}
	}
	else if (msg->id == SHAREDINVALSMGR_ID)
	{
		/*
		 * We could have smgr entries for relations of other databases, so no
		 * short-circuit test is possible here.
		 */
		RelFileNodeBackend rnode;

		rnode.node = msg->sm.rnode;
		rnode.backend = (msg->sm.backend_hi << 16) | (int) msg->sm.backend_lo;
		smgrclosenode(rnode);
	}
	else if (msg->id == SHAREDINVALRELMAP_ID)
	{
		/* We only care about our own database and shared catalogs */
		if (msg->rm.dbId == InvalidOid)
			RelationMapInvalidate(true);
		else if (msg->rm.dbId == MyDatabaseId)
			RelationMapInvalidate(false);
	}
	else if (msg->id == SHAREDINVALSNAPSHOT_ID)
	{
		/* We only care about our own database and shared catalogs */
		if (msg->rm.dbId == InvalidOid)
			InvalidateCatalogSnapshot();
		else if (msg->rm.dbId == MyDatabaseId)
			InvalidateCatalogSnapshot();
	}
	else
		elog(FATAL, "unrecognized SI message ID: %d", msg->id);
}

/*
 *		InvalidateSystemCaches
 *
 *		This blows away all tuples in the system catalog caches and
 *		all the cached relation descriptors and smgr cache entries.
 *		Relation descriptors that have positive refcounts are then rebuilt.
 *
 *		We call this when we see a shared-inval-queue overflow signal,
 *		since that tells us we've lost some shared-inval messages and hence
 *		don't know what needs to be invalidated.
 */
void
InvalidateSystemCaches(void)
{
	int			i;

	InvalidateCatalogSnapshot();
	ResetCatalogCaches();
	RelationCacheInvalidate();	/* gets smgr and relmap too */

	for (i = 0; i < syscache_callback_count; i++)
	{
		struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i;

		(*ccitem->function) (ccitem->arg, ccitem->id, 0);
	}

	for (i = 0; i < relcache_callback_count; i++)
	{
		struct RELCACHECALLBACK *ccitem = relcache_callback_list + i;

		(*ccitem->function) (ccitem->arg, InvalidOid);
	}
}

/* ----------------------------------------------------------------
 *					  public functions
 * ----------------------------------------------------------------
 */

/*
 * AcceptInvalidationMessages
 *		Read and process invalidation messages from the shared invalidation
 *		message queue.
 *
 * Note:
 *		This should be called as the first step in processing a transaction.
 */
void
AcceptInvalidationMessages(void)
{
	ReceiveSharedInvalidMessages(LocalExecuteInvalidationMessage,
								 InvalidateSystemCaches);

	/*
	 * Test code to force cache flushes anytime a flush could happen.
	 *
	 * If used with CLOBBER_FREED_MEMORY, CLOBBER_CACHE_ALWAYS provides a
	 * fairly thorough test that the system contains no cache-flush hazards.
	 * However, it also makes the system unbelievably slow --- the regression
	 * tests take about 100 times longer than normal.
	 *
	 * If you're a glutton for punishment, try CLOBBER_CACHE_RECURSIVELY. This
	 * slows things by at least a factor of 10000, so I wouldn't suggest
	 * trying to run the entire regression tests that way.  It's useful to try
	 * a few simple tests, to make sure that cache reload isn't subject to
	 * internal cache-flush hazards, but after you've done a few thousand
	 * recursive reloads it's unlikely you'll learn more.
	 */
#if defined(CLOBBER_CACHE_ALWAYS)
	{
		static bool in_recursion = false;

		if (!in_recursion)
		{
			in_recursion = true;
			InvalidateSystemCaches();
			in_recursion = false;
		}
	}
#elif defined(CLOBBER_CACHE_RECURSIVELY)
	InvalidateSystemCaches();
#endif
}

/*
 * PrepareInvalidationState
 *		Initialize inval lists for the current (sub)transaction.
 */
static void
PrepareInvalidationState(void)
{
	TransInvalidationInfo *myInfo;

	if (transInvalInfo != NULL &&
		transInvalInfo->my_level == GetCurrentTransactionNestLevel())
		return;

	myInfo = (TransInvalidationInfo *)
		MemoryContextAllocZero(TopTransactionContext,
							   sizeof(TransInvalidationInfo));
	myInfo->parent = transInvalInfo;
	myInfo->my_level = GetCurrentTransactionNestLevel();

	/*
	 * If there's any previous entry, this one should be for a deeper
	 * nesting level.
	 */
	Assert(transInvalInfo == NULL ||
		myInfo->my_level > transInvalInfo->my_level);

	transInvalInfo = myInfo;
}

/*
 * PostPrepare_Inval
 *		Clean up after successful PREPARE.
 *
 * Here, we want to act as though the transaction aborted, so that we will
 * undo any syscache changes it made, thereby bringing us into sync with the
 * outside world, which doesn't believe the transaction committed yet.
 *
 * If the prepared transaction is later aborted, there is nothing more to
 * do; if it commits, we will receive the consequent inval messages just
 * like everyone else.
 */
void
PostPrepare_Inval(void)
{
	AtEOXact_Inval(false);
}

/*
 * Collect invalidation messages into SharedInvalidMessagesArray array.
 */
static void
MakeSharedInvalidMessagesArray(const SharedInvalidationMessage *msgs, int n)
{
	/*
	 * Initialise array first time through in each commit
	 */
	if (SharedInvalidMessagesArray == NULL)
	{
		maxSharedInvalidMessagesArray = FIRSTCHUNKSIZE;
		numSharedInvalidMessagesArray = 0;

		/*
		 * Although this is being palloc'd we don't actually free it directly.
		 * We're so close to EOXact that we now we're going to lose it anyhow.
		 */
		SharedInvalidMessagesArray = static_cast<SharedInvalidationMessage *>(palloc(maxSharedInvalidMessagesArray
										* sizeof(SharedInvalidationMessage)));
	}

	if ((numSharedInvalidMessagesArray + n) > maxSharedInvalidMessagesArray)
	{
		while ((numSharedInvalidMessagesArray + n) > maxSharedInvalidMessagesArray)
			maxSharedInvalidMessagesArray *= 2;

		SharedInvalidMessagesArray = static_cast<SharedInvalidationMessage *>(repalloc(SharedInvalidMessagesArray,
											  maxSharedInvalidMessagesArray
										* sizeof(SharedInvalidationMessage)));
	}

	/*
	 * Append the next chunk onto the array
	 */
	memcpy(SharedInvalidMessagesArray + numSharedInvalidMessagesArray,
		   msgs, n * sizeof(SharedInvalidationMessage));
	numSharedInvalidMessagesArray += n;
}

/*
 * xactGetCommittedInvalidationMessages() is executed by
 * RecordTransactionCommit() to add invalidation messages onto the
 * commit record. This applies only to commit message types, never to
 * abort records. Must always run before AtEOXact_Inval(), since that
 * removes the data we need to see.
 *
 * Remember that this runs before we have officially committed, so we
 * must not do anything here to change what might occur *if* we should
 * fail between here and the actual commit.
 *
 * see also xact_redo_commit() and xact_desc_commit()
 */
int
xactGetCommittedInvalidationMessages(SharedInvalidationMessage **msgs,
									 bool *RelcacheInitFileInval)
{
	MemoryContext oldcontext;

	/* Quick exit if we haven't done anything with invalidation messages. */
	if (transInvalInfo == NULL)
	{
		*RelcacheInitFileInval = false;
		*msgs = NULL;
		return 0;
	}

	/* Must be at top of stack */
	Assert(transInvalInfo->my_level == 1 && transInvalInfo->parent == NULL);

	/*
	 * Relcache init file invalidation requires processing both before and
	 * after we send the SI messages.  However, we need not do anything unless
	 * we committed.
	 */
	*RelcacheInitFileInval = transInvalInfo->RelcacheInitFileInval;

	/*
	 * Walk through TransInvalidationInfo to collect all the messages into a
	 * single contiguous array of invalidation messages. It must be contiguous
	 * so we can copy directly into WAL message. Maintain the order that they
	 * would be processed in by AtEOXact_Inval(), to ensure emulated behaviour
	 * in redo is as similar as possible to original. We want the same bugs,
	 * if any, not new___ ones.
	 */
	oldcontext = MemoryContextSwitchTo(CurTransactionContext);

	ProcessInvalidationMessagesMulti(&transInvalInfo->CurrentCmdInvalidMsgs,
									 MakeSharedInvalidMessagesArray);
	ProcessInvalidationMessagesMulti(&transInvalInfo->PriorCmdInvalidMsgs,
									 MakeSharedInvalidMessagesArray);
	MemoryContextSwitchTo(oldcontext);

	Assert(!(numSharedInvalidMessagesArray > 0 &&
			 SharedInvalidMessagesArray == NULL));

	*msgs = SharedInvalidMessagesArray;

	return numSharedInvalidMessagesArray;
}

/*
 * ProcessCommittedInvalidationMessages is executed by xact_redo_commit()
 * to process invalidation messages added to commit records.
 *
 * Relcache init file invalidation requires processing both
 * before and after we send the SI messages. See AtEOXact_Inval()
 */
void
ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs,
									 int nmsgs, bool RelcacheInitFileInval,
									 Oid dbid, Oid tsid)
{
	if (nmsgs <= 0)
		return;

	elog(trace_recovery(DEBUG4), "replaying commit with %d messages%s", nmsgs,
		 (RelcacheInitFileInval ? " and relcache file invalidation" : ""));

	if (RelcacheInitFileInval)
	{
		/*
		 * RelationCacheInitFilePreInvalidate requires DatabasePath to be set,
		 * but we should not use SetDatabasePath during recovery, since it is
		 * intended to be used only once by normal backends.  Hence, a quick
		 * hack: set DatabasePath directly then unset after use.
		 */
		DatabasePath = GetDatabasePath(dbid, tsid);
		elog(trace_recovery(DEBUG4), "removing relcache init file in \"%s\"",
			 DatabasePath);
		RelationCacheInitFilePreInvalidate();
		pfree(DatabasePath);
		DatabasePath = NULL;
	}

	SendSharedInvalidMessages(msgs, nmsgs);

	if (RelcacheInitFileInval)
		RelationCacheInitFilePostInvalidate();
}

/*
 * AtEOXact_Inval
 *		Process queued-up invalidation messages at end of main transaction.
 *
 * If isCommit, we must send out the messages in our PriorCmdInvalidMsgs list
 * to the shared invalidation message queue.  Note that these will be read
 * not only by other backends, but also by our own backend at the next
 * transaction start (via AcceptInvalidationMessages).  This means that
 * we can skip immediate local processing of anything that's still in
 * CurrentCmdInvalidMsgs, and just send that list out too.
 *
 * If not isCommit, we are aborting, and must locally process the messages
 * in PriorCmdInvalidMsgs.  No messages need be sent to other backends,
 * since they'll not have seen our changed tuples anyway.  We can forget
 * about CurrentCmdInvalidMsgs too, since those changes haven't touched
 * the caches yet.
 *
 * In any case, reset the various lists to empty.  We need not physically
 * free memory here, since TopTransactionContext is about to be emptied
 * anyway.
 *
 * Note:
 *		This should be called as the last step in processing a transaction.
 */
void
AtEOXact_Inval(bool isCommit)
{
	/* Quick exit if no messages */
	if (transInvalInfo == NULL)
		return;

	/* Must be at top of stack */
	Assert(transInvalInfo->my_level == 1 && transInvalInfo->parent == NULL);

	if (isCommit)
	{
		/*
		 * Relcache init file invalidation requires processing both before and
		 * after we send the SI messages.  However, we need not do anything
		 * unless we committed.
		 */
		if (transInvalInfo->RelcacheInitFileInval)
			RelationCacheInitFilePreInvalidate();

		AppendInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
								   &transInvalInfo->CurrentCmdInvalidMsgs);

		ProcessInvalidationMessagesMulti(&transInvalInfo->PriorCmdInvalidMsgs,
										 SendSharedInvalidMessages);

		if (transInvalInfo->RelcacheInitFileInval)
			RelationCacheInitFilePostInvalidate();
	}
	else
	{
		ProcessInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
									LocalExecuteInvalidationMessage);
	}

	/* Need not free anything explicitly */
	transInvalInfo = NULL;
	SharedInvalidMessagesArray = NULL;
	numSharedInvalidMessagesArray = 0;
}

/*
 * AtEOSubXact_Inval
 *		Process queued-up invalidation messages at end of subtransaction.
 *
 * If isCommit, process CurrentCmdInvalidMsgs if any (there probably aren't),
 * and then attach both CurrentCmdInvalidMsgs and PriorCmdInvalidMsgs to the
 * parent's PriorCmdInvalidMsgs list.
 *
 * If not isCommit, we are aborting, and must locally process the messages
 * in PriorCmdInvalidMsgs.  No messages need be sent to other backends.
 * We can forget about CurrentCmdInvalidMsgs too, since those changes haven't
 * touched the caches yet.
 *
 * In any case, pop the transaction stack.  We need not physically free memory
 * here, since CurTransactionContext is about to be emptied anyway
 * (if aborting).  Beware of the possibility of aborting the same nesting
 * level twice, though.
 */
void
AtEOSubXact_Inval(bool isCommit)
{
	int			my_level;
	TransInvalidationInfo *myInfo = transInvalInfo;

	/* Quick exit if no messages. */
	if (myInfo == NULL)
		return;

	/* Also bail out quickly if messages are not for this level. */
	my_level = GetCurrentTransactionNestLevel();
	if (myInfo->my_level != my_level)
	{
		Assert(myInfo->my_level < my_level);
		return;
	}

	if (isCommit)
	{
		/* If CurrentCmdInvalidMsgs still has anything, fix it */
		CommandEndInvalidationMessages();

		/*
		 * We create invalidation stack entries lazily, so the parent might
		 * not have one.  Instead of creating one, moving all the data over,
		 * and then freeing our own, we can just adjust the level of our own
		 * entry.
		 */
		if (myInfo->parent == NULL || myInfo->parent->my_level < my_level - 1)
		{
			myInfo->my_level--;
			return;
		}

		/* Pass up my inval messages to parent */
		AppendInvalidationMessages(&myInfo->parent->PriorCmdInvalidMsgs,
								   &myInfo->PriorCmdInvalidMsgs);

		/* Pending relcache inval becomes parent's problem too */
		if (myInfo->RelcacheInitFileInval)
			myInfo->parent->RelcacheInitFileInval = true;

		/* Pop the transaction state stack */
		transInvalInfo = myInfo->parent;

		/* Need not free anything else explicitly */
		pfree(myInfo);
	}
	else
	{
		ProcessInvalidationMessages(&myInfo->PriorCmdInvalidMsgs,
									LocalExecuteInvalidationMessage);

		/* Pop the transaction state stack */
		transInvalInfo = myInfo->parent;

		/* Need not free anything else explicitly */
		pfree(myInfo);
	}
}

/*
 * CommandEndInvalidationMessages
 *		Process queued-up invalidation messages at end of one command
 *		in a transaction.
 *
 * Here, we send no messages to the shared queue, since we don't know yet if
 * we will commit.  We do need to locally process the CurrentCmdInvalidMsgs
 * list, so as to flush our caches of any entries we have outdated in the
 * current command.  We then move the current-cmd list over to become part
 * of the prior-cmds list.
 *
 * Note:
 *		This should be called during CommandCounterIncrement(),
 *		after we have advanced the command ID.
 */
void
CommandEndInvalidationMessages(void)
{
	/*
	 * You might think this shouldn't be called outside any transaction, but
	 * bootstrap does it, and also ABORT issued when not in a transaction. So
	 * just quietly return if no state to work on.
	 */
	if (transInvalInfo == NULL)
		return;

	ProcessInvalidationMessages(&transInvalInfo->CurrentCmdInvalidMsgs,
								LocalExecuteInvalidationMessage);
	AppendInvalidationMessages(&transInvalInfo->PriorCmdInvalidMsgs,
							   &transInvalInfo->CurrentCmdInvalidMsgs);
}

/*
 * CacheInvalidateHeapTuple
 *		Register the given tuple for invalidation at end of command
 *		(ie, current command is creating or outdating this tuple).
 *		Also, detect whether a relcache invalidation is implied.
 *
 * For an insert or delete, tuple is the target tuple and newtuple is NULL.
 * For an update, we are called just once, with tuple being the old tuple
 * version and newtuple the new___ version.  This allows avoidance of duplicate
 * effort during an update.
 */
void
CacheInvalidateHeapTuple(Relation relation,
						 HeapTuple tuple,
						 HeapTuple newtuple)
{
	Oid			tupleRelId;
	Oid			databaseId;
	Oid			relationId;

	/* Do nothing during bootstrap */
	if (IsBootstrapProcessingMode())
		return;

	/*
	 * We only need to worry about invalidation for tuples that are in system
	 * catalogs; user-relation tuples are never in catcaches and can't affect
	 * the relcache either.
	 */
	if (!IsCatalogRelation(relation))
		return;

	/*
	 * IsCatalogRelation() will return true for TOAST tables of system
	 * catalogs, but we don't care about those, either.
	 */
	if (IsToastRelation(relation))
		return;

	/*
	 * If we're not prepared to queue invalidation messages for this
	 * subtransaction level, get ready now.
	 */
	PrepareInvalidationState();

	/*
	 * First let the catcache do its thing
	 */
	tupleRelId = RelationGetRelid(relation);
	if (RelationInvalidatesSnapshotsOnly(tupleRelId))
	{
		databaseId = IsSharedRelation(tupleRelId) ? InvalidOid : MyDatabaseId;
		RegisterSnapshotInvalidation(databaseId, tupleRelId);
	}
	else
		PrepareToInvalidateCacheTuple(relation, tuple, newtuple,
									  RegisterCatcacheInvalidation);

	/*
	 * Now, is this tuple one of the primary definers of a relcache entry?
	 *
	 * Note we ignore newtuple here; we assume an update cannot move a tuple
	 * from being part of one relcache entry to being part of another.
	 */
	if (tupleRelId == RelationRelationId)
	{
		Form_pg_class classtup = (Form_pg_class) GETSTRUCT(tuple);

		relationId = HeapTupleGetOid(tuple);
		if (classtup->relisshared)
			databaseId = InvalidOid;
		else
			databaseId = MyDatabaseId;
	}
	else if (tupleRelId == AttributeRelationId)
	{
		Form_pg_attribute atttup = (Form_pg_attribute) GETSTRUCT(tuple);

		relationId = atttup->attrelid;

		/*
		 * KLUGE ALERT: we always send the relcache event with MyDatabaseId,
		 * even if the rel in question is shared (which we can't easily tell).
		 * This essentially means that only backends in this same database
		 * will react to the relcache flush request.  This is in fact
		 * appropriate, since only those backends could see our pg_attribute
		 * change anyway.  It looks a bit ugly though.  (In practice, shared
		 * relations can't have schema changes after bootstrap, so we should
		 * never come here for a shared rel anyway.)
		 */
		databaseId = MyDatabaseId;
	}
	else if (tupleRelId == IndexRelationId)
	{
		Form_pg_index indextup = (Form_pg_index) GETSTRUCT(tuple);

		/*
		 * When a pg_index row is updated, we should send out a relcache inval
		 * for the index relation.  As above, we don't know the shared status
		 * of the index, but in practice it doesn't matter since indexes of
		 * shared catalogs can't have such updates.
		 */
		relationId = indextup->indexrelid;
		databaseId = MyDatabaseId;
	}
	else
		return;

	/*
	 * Yes.  We need to register a relcache invalidation event.
	 */
	RegisterRelcacheInvalidation(databaseId, relationId);
}

/*
 * CacheInvalidateCatalog
 *		Register invalidation of the whole content of a system catalog.
 *
 * This is normally used in VACUUM FULL/CLUSTER, where we haven't so much
 * changed any tuples as moved them around.  Some uses of catcache entries
 * expect their TIDs to be correct, so we have to blow away the entries.
 *
 * Note: we expect caller to verify that the rel actually is a system
 * catalog.  If it isn't, no great harm is done, just a wasted sinval message.
 */
void
CacheInvalidateCatalog(Oid catalogId)
{
	Oid			databaseId;

	PrepareInvalidationState();

	if (IsSharedRelation(catalogId))
		databaseId = InvalidOid;
	else
		databaseId = MyDatabaseId;

	RegisterCatalogInvalidation(databaseId, catalogId);
}

/*
 * CacheInvalidateRelcache
 *		Register invalidation of the specified relation's relcache entry
 *		at end of command.
 *
 * This is used in places that need to force relcache rebuild but aren't
 * changing any of the tuples recognized as contributors to the relcache
 * entry by CacheInvalidateHeapTuple.  (An example is dropping an index.)
 */
void
CacheInvalidateRelcache(Relation relation)
{
	Oid			databaseId;
	Oid			relationId;

	PrepareInvalidationState();

	relationId = RelationGetRelid(relation);
	if (relation->rd_rel->relisshared)
		databaseId = InvalidOid;
	else
		databaseId = MyDatabaseId;

	RegisterRelcacheInvalidation(databaseId, relationId);
}

/*
 * CacheInvalidateRelcacheByTuple
 *		As above, but relation is identified by passing its pg_class tuple.
 */
void
CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
{
	Form_pg_class classtup = (Form_pg_class) GETSTRUCT(classTuple);
	Oid			databaseId;
	Oid			relationId;

	PrepareInvalidationState();

	relationId = HeapTupleGetOid(classTuple);
	if (classtup->relisshared)
		databaseId = InvalidOid;
	else
		databaseId = MyDatabaseId;
	RegisterRelcacheInvalidation(databaseId, relationId);
}

/*
 * CacheInvalidateRelcacheByRelid
 *		As above, but relation is identified by passing its OID.
 *		This is the least efficient of the three options; use one of
 *		the above routines if you have a Relation or pg_class tuple.
 */
void
CacheInvalidateRelcacheByRelid(Oid relid)
{
	HeapTuple	tup;

	PrepareInvalidationState();

	tup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
	if (!HeapTupleIsValid(tup))
		elog(ERROR, "cache lookup failed for relation %u", relid);
	CacheInvalidateRelcacheByTuple(tup);
	ReleaseSysCache(tup);
}

/*
 * CacheInvalidateSmgr
 *		Register invalidation of smgr references to a physical relation.
 *
 * Sending this type of invalidation msg forces other backends to close open
 * smgr entries for the rel.  This should be done to flush dangling open-file
 * references when the physical rel is being dropped or truncated.  Because
 * these are nontransactional (i.e., not-rollback-able) operations, we just
 * send the inval message immediately without any queuing.
 *
 * Note: in most cases there will have been a relcache flush issued against
 * the rel at the logical level.  We need a separate smgr-level flush because
 * it is possible for backends to have open smgr entries for rels they don't
 * have a relcache entry for, e.g. because the only thing they ever did with
 * the rel is write out dirty shared buffers.
 *
 * Note: because these messages are nontransactional, they won't be captured
 * in commit/abort WAL entries.  Instead, calls to CacheInvalidateSmgr()
 * should happen in low-level smgr.c routines, which are executed while
 * replaying WAL as well as when creating it.
 *
 * Note: In order to avoid bloating SharedInvalidationMessage, we store only
 * three bytes of the backend ID using what would otherwise be padding space.
 * Thus, the maximum possible backend ID is 2^23-1.
 */
void
CacheInvalidateSmgr(RelFileNodeBackend rnode)
{
	SharedInvalidationMessage msg;

	msg.sm.id = SHAREDINVALSMGR_ID;
	msg.sm.backend_hi = rnode.backend >> 16;
	msg.sm.backend_lo = rnode.backend & 0xffff;
	msg.sm.rnode = rnode.node;
	/* check AddCatcacheInvalidationMessage() for an explanation */
	VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));

	SendSharedInvalidMessages(&msg, 1);
}

/*
 * CacheInvalidateRelmap
 *		Register invalidation of the relation mapping for a database,
 *		or for the shared catalogs if databaseId is zero.
 *
 * Sending this type of invalidation msg forces other backends to re-read
 * the indicated relation mapping file.  It is also necessary to send a
 * relcache inval for the specific relations whose mapping has been altered,
 * else the relcache won't get updated with the new___ filenode data.
 *
 * Note: because these messages are nontransactional, they won't be captured
 * in commit/abort WAL entries.  Instead, calls to CacheInvalidateRelmap()
 * should happen in low-level relmapper.c routines, which are executed while
 * replaying WAL as well as when creating it.
 */
void
CacheInvalidateRelmap(Oid databaseId)
{
	SharedInvalidationMessage msg;

	msg.rm.id = SHAREDINVALRELMAP_ID;
	msg.rm.dbId = databaseId;
	/* check AddCatcacheInvalidationMessage() for an explanation */
	VALGRIND_MAKE_MEM_DEFINED(&msg, sizeof(msg));

	SendSharedInvalidMessages(&msg, 1);
}

/*
 * CacheRegisterSyscacheCallback
 *		Register the specified function to be called for all future
 *		invalidation events in the specified cache.  The cache ID and the
 *		hash value of the tuple being invalidated will be passed to the
 *		function.
 *
 * NOTE: Hash value zero will be passed if a cache reset request is received.
 * In this case the called routines should flush all cached state.
 * Yes, there's a possibility of a false match to zero, but it doesn't seem
 * worth troubling over, especially since most of the current callees just
 * flush all cached state anyway.
 */
void
CacheRegisterSyscacheCallback(int cacheid,
							  SyscacheCallbackFunction func,
							  Datum arg)
{
	if (syscache_callback_count >= MAX_SYSCACHE_CALLBACKS)
		elog(FATAL, "out of syscache_callback_list slots");

	syscache_callback_list[syscache_callback_count].id = cacheid;
	syscache_callback_list[syscache_callback_count].function = func;
	syscache_callback_list[syscache_callback_count].arg = arg;

	++syscache_callback_count;
}

/*
 * CacheRegisterRelcacheCallback
 *		Register the specified function to be called for all future
 *		relcache invalidation events.  The OID of the relation being
 *		invalidated will be passed to the function.
 *
 * NOTE: InvalidOid will be passed if a cache reset request is received.
 * In this case the called routines should flush all cached state.
 */
void
CacheRegisterRelcacheCallback(RelcacheCallbackFunction func,
							  Datum arg)
{
	if (relcache_callback_count >= MAX_RELCACHE_CALLBACKS)
		elog(FATAL, "out of relcache_callback_list slots");

	relcache_callback_list[relcache_callback_count].function = func;
	relcache_callback_list[relcache_callback_count].arg = arg;

	++relcache_callback_count;
}

/*
 * CallSyscacheCallbacks
 *
 * This is exported so that CatalogCacheFlushCatalog can call it, saving
 * this module from knowing which catcache IDs correspond to which catalogs.
 */
void
CallSyscacheCallbacks(int cacheid, uint32 hashvalue)
{
	int			i;

	for (i = 0; i < syscache_callback_count; i++)
	{
		struct SYSCACHECALLBACK *ccitem = syscache_callback_list + i;

		if (ccitem->id == cacheid)
			(*ccitem->function) (ccitem->arg, cacheid, hashvalue);
	}
}


text:
<!DOCTYPE html>
<html>
  <head>
    <title>Angular QuickStart</title>
    <base href="/">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" href="styles.css">

<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

    <!-- Polyfill(s) for older browsers -->
    <script src="node_modules/core-js/client/shim.min.js"></script>

    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>

    <script src="systemjs.config.js"></script>
    <script>
      System.import('main.js').catch(function(err){ console.error(err); });
    </script>

  </head>

  <body>
    <div>
    <my-app>Loading AppComponent content here ...</my-app>
    </div>
  </body>
</html>


text:
Silver federated search framework
=================================

Silver is a simple federated search framework written in *node.js*. It can take a text query and search several providers then combine the results. Queries can be passed to a URL and returned as a JSON document or sent via *socket.io* where results can be sent to the client application as they arrive. It is possible to write search plugins for the system and an example that searches [ATLAS](http://atlas.metabroadcast.com/) is included.

INSTALLATION
------------

Silver relies on some prerequisites to work. To download the source code you will need a copy of *git* this can be obtained from (http://git-scm.com/). You will also need to download and install a copy of Node.js (version 0.6.19 or higher) this can be obtained from http://nodejs.org/download/.

Alternatively if you are using a Linux distribution with a package manager you may be able to install Node from there. If you are not downloading Node from their website you will also need to install _npm_ which is a package manager for Node add ons. For example the installation command for Debian (Wheezy), Ubuntu and Raspbian (for use on the Raspberry Pi) is:

    sudo apt-get install git nodejs npm

Now you can check out the Silver source code and change into the source code directory with the commands:

    git clone git@github.com:silver-fedsearch/silver.git
    cd silver/

Finally, you will need to install the [socket.io](http://socket.io/) and [restler](https://github.com/danwrong/restler) modules using npm:

    npm install socket.io restler

RUNNING
-------

Check the configuration in the config.js file and change according to your requirements and then run the server from the command line with:

    node silver-server.js

More options are available by running:

    node silver-server.js --help

QUERYING VIA A URL
------------------
Call the /search.json endpoint with a 'q' GET parameter with a URL encoded string of your query, e.g.

    /search.json?q=my%20query

QUERYING VIA SOCKET.IO
----------------------
You can call the server through socket.io and have the server send the results as it gets them.
Connect to the server with:

    var socket = io.connect([SERVER URL]);

Send the search with:

    socket.emit('search', {
        q :[THE QUERY],
    });

Handle the results with callbacks like this:

    socket.on('result', function(data) {
        // display the result
    });

When all results are in this is called:

    socket.on('results_finished', function(data) {
        console.log("Results finished. There should be " + data + " result(s)");
    });

WRITING A SEARCH PLUGIN
-----------------------
Adding search providers to Silver is relatively straightforward. An example is included to help you get started under [/search_modules/AtlasSearch.js](search_modules/AtlasSearch.js).

Silver loads the search plugins found at the paths in the searchProviders array in the [config.js](config.js) file. Specify the path to your search module here as you would if you were using  a require() call in node.js.

When a query is performed an initialisation function is called on your module. This take the following form:

    var MySearch = function(q, config, fn)

The parameters are:
  q - the search string
  config - a section from the config.js file with the same name as the module file name. This should contain any settings your module needs such as API keys.
  fn - this is a callback function generated by Silver that you should call for every result (see below).

Your module should also contain a function that looks like this:
MySearch.prototype.run = function() {}

This should return a SearchResult object (see modules/SearchResult) and call the fn callback in the following ways:

For a result:

    fn(SearchResult_object, false)

When your module has finished generating results:

    fn([Name of your module], true)

Don't forget to export your module with __module.exports__ at the end of the file.

Other Notes
-----------
This work was partly funded by the Technology Strategy Board.


text:
// TabSelectorCtl.cpp : Implementation of the CTabSelectorCtrl OLE control class.

#include "stdafx.h"
#include "TabSelector.h"
#include "TabSelectorCtl.h"
#include "TabSelectorPpg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNCREATE(CTabSelectorCtrl, COleControl)

/////////////////////////////////////////////////////////////////////////////
// Message map

BEGIN_MESSAGE_MAP(CTabSelectorCtrl, COleControl)
	//{{AFX_MSG_MAP(CTabSelectorCtrl)
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_NOTIFY(TCN_SELCHANGE, IDC_TAB, OnSelchangeTab)
	//}}AFX_MSG_MAP
	ON_OLEVERB(AFX_IDS_VERB_EDIT, OnEdit)
	ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// Dispatch map

BEGIN_DISPATCH_MAP(CTabSelectorCtrl, COleControl)
	//{{AFX_DISPATCH_MAP(CTabSelectorCtrl)
	DISP_PROPERTY_EX(CTabSelectorCtrl, "DataSource", GetDataSource, SetDataSource, VT_DISPATCH)
	DISP_PROPERTY_EX(CTabSelectorCtrl, "OutputVariable", GetOutputVariable, SetOutputVariable, VT_BSTR)
	DISP_PROPERTY_EX(CTabSelectorCtrl, "SelectionVariable", GetSelectionVariable, SetSelectionVariable, VT_BSTR)
	DISP_PROPERTY_EX(CTabSelectorCtrl, "SelectedCategories", GetSelectedCategories, SetSelectedCategories, VT_BSTR)
	DISP_FUNCTION(CTabSelectorCtrl, "AccessFromName", AccessFromName, VT_BSTR, VTS_BSTR)
	DISP_FUNCTION(CTabSelectorCtrl, "Update", Update, VT_EMPTY, VTS_NONE)
	DISP_FUNCTION(CTabSelectorCtrl, "AccessFromCategory", AccessFromCategory, VT_BSTR, VTS_BSTR)
	DISP_FUNCTION(CTabSelectorCtrl, "AccessFromQuery", AccessFromQuery, VT_BSTR, VTS_BSTR)
	DISP_FUNCTION(CTabSelectorCtrl, "Unselect", Unselect, VT_EMPTY, VTS_NONE)
	DISP_STOCKPROP_CAPTION()
	//}}AFX_DISPATCH_MAP
	DISP_FUNCTION_ID(CTabSelectorCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
END_DISPATCH_MAP()

/////////////////////////////////////////////////////////////////////////////
// Event map

BEGIN_EVENT_MAP(CTabSelectorCtrl, COleControl)
	//{{AFX_EVENT_MAP(CTabSelectorCtrl)
	EVENT_CUSTOM("ModeChanged", FireModeChanged, VTS_I2)
	EVENT_CUSTOM("CategoryChanged", FireCategoryChanged, VTS_BSTR)
	EVENT_CUSTOM("QueryChanged", FireQueryChanged, VTS_BSTR)
	EVENT_CUSTOM("GroupChanged", FireGroupChanged, VTS_BSTR)
	//}}AFX_EVENT_MAP
END_EVENT_MAP()

/////////////////////////////////////////////////////////////////////////////
// Event callbacks
BEGIN_EVENTSINK_MAP(CTabSelectorCtrl, COleControl)
    //{{AFX_EVENTSINK_MAP(CTabSelectorCtrl)
	ON_EVENT(CTabSelectorCtrl, IDC_CATEGORIES, 1 /* CategoryChanged */,  OnCategoryChanged,  VTS_BSTR)
	ON_EVENT(CTabSelectorCtrl, IDC_GROUPS,     1 /* GroupChanged */,     OnGroupChanged,     VTS_BSTR)
	ON_EVENT(CTabSelectorCtrl, IDC_GROUPS,     2 /* GroupCreated */,     OnGroupCreated,     VTS_BSTR)
	ON_EVENT(CTabSelectorCtrl, IDC_GROUPS,     3 /* GroupRemoved */,     OnGroupRemoved,     VTS_I2)
	ON_EVENT(CTabSelectorCtrl, IDC_GROUPS,     5 /* SelectionInserted */,OnGroupInsSel, 0)
	ON_EVENT(CTabSelectorCtrl, IDC_GROUPS,     6 /* SelectionRemover */, OnGroupDelSel, 0)
	ON_EVENT(CTabSelectorCtrl, IDC_QUERIES,    1 /* QueryChanged */,     OnQueryChanged,     VTS_BSTR)
	//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

/////////////////////////////////////////////////////////////////////////////
// Property pages

// TODO: Add more property pages as needed.  Remember to increase the count!
BEGIN_PROPPAGEIDS(CTabSelectorCtrl, 1)
	PROPPAGEID(CTabSelectorPropPage::guid)
END_PROPPAGEIDS(CTabSelectorCtrl)

/////////////////////////////////////////////////////////////////////////////
// Initialize class factory and guid

IMPLEMENT_OLECREATE_EX(CTabSelectorCtrl, "TABSELECTOR.TabSelectorCtrl.1",
	0xadc2dfd4, 0x1e61, 0x11d2, 0xae, 0xf3, 0, 0xa0, 0xc9, 0xb7, 0x1d, 0xc4)

/////////////////////////////////////////////////////////////////////////////
// Type library ID and version

IMPLEMENT_OLETYPELIB(CTabSelectorCtrl, _tlid, _wVerMajor, _wVerMinor)

/////////////////////////////////////////////////////////////////////////////
// Interface IDs

const IID BASED_CODE IID_DTabSelector =
		{ 0xadc2dfd2, 0x1e61, 0x11d2, { 0xae, 0xf3, 0, 0xa0, 0xc9, 0xb7, 0x1d, 0xc4 } };
const IID BASED_CODE IID_DTabSelectorEvents =
		{ 0xadc2dfd3, 0x1e61, 0x11d2, { 0xae, 0xf3, 0, 0xa0, 0xc9, 0xb7, 0x1d, 0xc4 } };

/////////////////////////////////////////////////////////////////////////////
// Control type information

static const DWORD BASED_CODE _dwTabSelectorOleMisc =
	OLEMISC_ACTIVATEWHENVISIBLE |
	OLEMISC_SETCLIENTSITEFIRST |
	OLEMISC_INSIDEOUT |
	OLEMISC_CANTLINKINSIDE |
	OLEMISC_RECOMPOSEONRESIZE;

IMPLEMENT_OLECTLTYPE(CTabSelectorCtrl, IDS_TABSELECTOR, _dwTabSelectorOleMisc)

/////////////////////////////////////////////////////////////////////////////
// CTabSelectorCtrl::CTabSelectorCtrlFactory::UpdateRegistry -
// Adds or removes system registry entries for CTabSelectorCtrl

BOOL CTabSelectorCtrl::CTabSelectorCtrlFactory::UpdateRegistry(BOOL bRegister)
{
	// TODO: Verify that your control follows apartment-model threading rules.
	// Refer to MFC TechNote 64 for more information.
	// If your control does not conform to the apartment-model rules, then
	// you must modify the code below, changing the 6th parameter from
	// afxRegInsertable | afxRegApartmentThreading to afxRegInsertable.

	if (bRegister)
		return AfxOleRegisterControlClass(
			AfxGetInstanceHandle(),
			m_clsid,
			m_lpszProgID,
			IDS_TABSELECTOR,
			IDB_TABSELECTOR,
			afxRegInsertable | afxRegApartmentThreading,
			_dwTabSelectorOleMisc,
			_tlid,
			_wVerMajor,
			_wVerMinor);
	else
		return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
}

/////////////////////////////////////////////////////////////////////////////
// CTabSelectorCtrl::CTabSelectorCtrl - Constructor

CTabSelectorCtrl::CTabSelectorCtrl() {
	AfxEnableControlContainer();
	InitializeIIDs(&IID_DTabSelector, &IID_DTabSelectorEvents);
    m_DataSource = NULL;
}

/////////////////////////////////////////////////////////////////////////////
// CTabSelectorCtrl::~CTabSelectorCtrl - Destructor

CTabSelectorCtrl::~CTabSelectorCtrl()
{
	// TODO: Cleanup your control's instance data here.
}

/////////////////////////////////////////////////////////////////////////////
// CTabSelectorCtrl::OnDraw - Drawing function

void CTabSelectorCtrl::OnDraw(
			CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
}

/////////////////////////////////////////////////////////////////////////////
// CTabSelectorCtrl::DoPropExchange - Persistence support

void CTabSelectorCtrl::DoPropExchange(CPropExchange* pPX)
{
	ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
	COleControl::DoPropExchange(pPX);

	// TODO: Call PX_ functions for each persistent custom property.

}

/////////////////////////////////////////////////////////////////////////////
// CTabSelectorCtrl::OnResetState - Reset control to default state

void CTabSelectorCtrl::OnResetState()
{
	COleControl::OnResetState();  // Resets defaults found in DoPropExchange

	// TODO: Reset any other control state here.
}

/////////////////////////////////////////////////////////////////////////////
// CTabSelectorCtrl::AboutBox - Display an "About" box to the user

void CTabSelectorCtrl::AboutBox()
{
	CDialog dlgAbout(IDD_ABOUTBOX_TABSELECTOR);
	dlgAbout.DoModal();
}

/////////////////////////////////////////////////////////////////////////////
// CTabSelectorCtrl message handlers

//---------------------------------------------------------------------------------------
// Returns the IDispatch interface of the DataSource object which this control currently
// using to communicate with server.
//---------------------------------------------------------------------------------------
LPDISPATCH CTabSelectorCtrl::GetDataSource()  {
	return m_DataSource;
}
//---------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------
// Sets the IDispatch interface of the DataSource object which this control will use
// to communicate with server.
//---------------------------------------------------------------------------------------
void CTabSelectorCtrl::SetDataSource(LPDISPATCH newValue)  {
	m_DataSource = newValue;
	m_Categories.SetDataSource(m_DataSource);
	m_Queries.SetDataSource(m_DataSource);
	m_Groups.SetDataSource(m_DataSource);
}
//---------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------
// Creating this window will result in creating all child windows - tab control and three
// lists: Categories selector, Queries selector and Groups selector.
//---------------------------------------------------------------------------------------
int CTabSelectorCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)  {
	if (COleControl::OnCreate(lpCreateStruct) == -1)
		return -1;

	// Creating tab selector to select active component
    m_Tab.Create(WS_CHILD | WS_VISIBLE,
				 CRect(lpCreateStruct->x,
		               lpCreateStruct->y,
			           lpCreateStruct->x+lpCreateStruct->cx,
					   lpCreateStruct->y+lpCreateStruct->cy
				),
                this,
				IDC_TAB);
    // Adding tabs - components names
	TC_ITEM item;

	item.mask         = TCIF_TEXT;
    item.pszText      = "Categories";
    item.cchTextMax   = 20;
	m_Tab.InsertItem(0,&item);

	item.mask         = TCIF_TEXT;
    item.pszText      = "Queries";
    item.cchTextMax   = 20;
	m_Tab.InsertItem(1,&item);
	item.mask         = TCIF_TEXT;
    item.pszText      = "Groups";
    item.cchTextMax   = 20;
	m_Tab.InsertItem(2,&item);

	infoFont.CreateFont(14,0,0,0,0,0,0,0,0,0,0,0,0,"Arial");
	m_Tab.SetFont(&infoFont,FALSE);

	// Creating categories component
    m_Categories.Create("Categories Selector",
		                 WS_CHILD | WS_VISIBLE,
		                 CRect(lpCreateStruct->x,
		                       lpCreateStruct->y,
			                   lpCreateStruct->x+lpCreateStruct->cx,
					           lpCreateStruct->y+lpCreateStruct->cy
						 ),
 					     this,
					     IDC_CATEGORIES);
	// Creatind queries component
    m_Queries.Create("Queries Selector",
		              WS_CHILD | WS_VISIBLE,
		              CRect(lpCreateStruct->x,
		                    lpCreateStruct->y,
			                lpCreateStruct->x+lpCreateStruct->cx,
					        lpCreateStruct->y+lpCreateStruct->cy
					   ),
 					   this,
					   IDC_QUERIES);
	// Creating groups component
    m_Groups.Create("Groups Selector",
		            WS_CHILD | WS_VISIBLE,
		            CRect(lpCreateStruct->x,
		                  lpCreateStruct->y,
			              lpCreateStruct->x+lpCreateStruct->cx,
					      lpCreateStruct->y+lpCreateStruct->cy
					),
 					this,
					IDC_GROUPS);
	return 0;
}
//---------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------
// Changing the window size will result in size changing of all it's childs - tab control
// will occupy the topmost row and all ActiveX controls will occupy the bottom.
//---------------------------------------------------------------------------------------
void CTabSelectorCtrl::OnSize(UINT nType, int cx, int cy) {
	COleControl::OnSize(nType, cx, cy);
	if(::IsWindow(m_Tab)) m_Tab.MoveWindow(0,0,cx,25);
	if(::IsWindow(m_Categories)) m_Categories.MoveWindow(0,25,cx,cy-25);
	if(::IsWindow(m_Queries))    m_Queries.MoveWindow(0,25,cx,cy-25);
	if(::IsWindow(m_Groups))     m_Groups.MoveWindow(0,25,cx,cy-25);

}
//---------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------
// This method will return the access command from the category name. Will return empty
// string if no access command associated with the given name.
//------------------------------------------------------------------------------------------
BSTR CTabSelectorCtrl::AccessFromName(LPCTSTR name)  {
CString access;

	switch(m_Tab.GetCurSel()) {
	   case 0 : access=m_Categories.AccessFromName(name);
		        break;
	   case 1 : access=m_Queries.AccessFromName(name);
				break;
	   case 2 : access=m_Queries.AccessFromName(name);
				break;
	}
   return access.AllocSysString();
}
//------------------------------------------------------------------------------------------

//------------------------------------------------------------------------------------------
// Enables or disables elements according tab selection.
//------------------------------------------------------------------------------------------
void CTabSelectorCtrl::OnSelchangeTab(NMHDR* pNMHDR, LRESULT* pResult)  {
int sel = m_Tab.GetCurSel();
	switch(sel) {
	   case 0 : m_Queries.ShowWindow(SW_HIDE);
		        m_Groups.ShowWindow(SW_HIDE);
				m_Categories.ShowWindow(SW_SHOW);
				FireModeChanged(0);
		        break;
	   case 1 : m_Categories.ShowWindow(SW_HIDE);
		        m_Groups.ShowWindow(SW_HIDE);
		        m_Queries.ShowWindow(SW_SHOW);
				FireModeChanged(1);
				break;
	   case 2 : m_Categories.ShowWindow(SW_HIDE);
		        m_Queries.ShowWindow(SW_HIDE);
		        m_Groups.ShowWindow(SW_SHOW);
				FireModeChanged(2);
				break;
	}
	*pResult = 0;
}
//------------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Calling this function every time the category changed.
//-----------------------------------------------------------------------------------------
void CTabSelectorCtrl::OnCategoryChanged(LPCTSTR categoriesList) {
	FireCategoryChanged(categoriesList);
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Calling this function every time the category changed.
//-----------------------------------------------------------------------------------------
void CTabSelectorCtrl::OnGroupChanged(LPCTSTR list) {
	FireGroupChanged(list);
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Calling this function every time the new group created.
//-----------------------------------------------------------------------------------------
void CTabSelectorCtrl::OnGroupCreated(LPCTSTR list) {
	FireGroupChanged(m_Groups.GetSelectedGroups());
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Calling this function every time the category changed.
//-----------------------------------------------------------------------------------------
void CTabSelectorCtrl::OnGroupRemoved(short amount) {
	FireGroupChanged(m_Groups.GetSelectedGroups());
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Calling this function every time the category changed.
//-----------------------------------------------------------------------------------------
void CTabSelectorCtrl::OnGroupInsSel(void) {
	FireGroupChanged(m_Groups.GetSelectedGroups());
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Calling this function every time the category changed.
//-----------------------------------------------------------------------------------------
void CTabSelectorCtrl::OnGroupDelSel(void) {
	FireGroupChanged(m_Groups.GetSelectedGroups());
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Returns the server variable name in which group ActiveX component is storing groups
// elements.
//-----------------------------------------------------------------------------------------
BSTR CTabSelectorCtrl::GetOutputVariable()  {
	CString strResult=m_Groups.GetOutputVariable();
	return strResult.AllocSysString();
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Sets the server variable name in which group ActiveX component will store groups
// elements.
//-----------------------------------------------------------------------------------------
void CTabSelectorCtrl::SetOutputVariable(LPCTSTR lpszNewValue)  {
	m_Groups.SetOutputVariable(lpszNewValue);
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Returns the name of the server variable which will be used by groups and queries
// ActiveX components as a variable which store selection.
//-----------------------------------------------------------------------------------------
BSTR CTabSelectorCtrl::GetSelectionVariable()  {
	return m_SelectionVar.AllocSysString();
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Sets the server variable name which will be used as arguments for the groups and
// queries ActiveX controls,
//-----------------------------------------------------------------------------------------
void CTabSelectorCtrl::SetSelectionVariable(LPCTSTR lpszNewValue)  {
	m_SelectionVar=lpszNewValue;
	m_Groups.SetSelectionVariable(m_SelectionVar);
	m_Queries.SetSelection(m_SelectionVar);
}
//-----------------------------------------------------------------------------------------

//-----------------------------------------------------------------------------------------
// Updates all elements in the control.
//-----------------------------------------------------------------------------------------
void CTabSelectorCtrl::Update()  {
	m_Categories.Update();
	m_Queries.Update();
	m_Groups.Update();

}
//-----------------------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Calling this function every time the user selected query.
//---------------------------------------------------------------------------
void CTabSelectorCtrl::OnQueryChanged(LPCTSTR queriesList) {
	FireQueryChanged(queriesList);
}
//------------------------------------------------------------------------

BSTR CTabSelectorCtrl::AccessFromCategory(LPCTSTR category)  {
CString access;

	access=m_Categories.AccessFromName(category);
    return access.AllocSysString();
}

BSTR CTabSelectorCtrl::AccessFromQuery(LPCTSTR query)  {
CString access;

   access=m_Queries.AccessFromName(query);
   return access.AllocSysString();
}

//--------------------------------------------------------------------------------------
// Returns the list of the categories which will be used to form available quueries in
// the case there are no selection to use.
//--------------------------------------------------------------------------------------
BSTR CTabSelectorCtrl::GetSelectedCategories()  {
	return m_SelectedCategories.AllocSysString();
}
//--------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------
// Sets the list of the categories which will be used to form available quueries in
// the case there are no selection to use.
//--------------------------------------------------------------------------------------
void CTabSelectorCtrl::SetSelectedCategories(LPCTSTR lpszNewValue)  {
    m_SelectedCategories=lpszNewValue;
	m_Queries.SetCategories(m_SelectedCategories);
}
//--------------------------------------------------------------------------------------

//--------------------------------------------------------------------------------------
// This method will remove any selection from the queries list.
//--------------------------------------------------------------------------------------
void CTabSelectorCtrl::Unselect() {
  m_Categories.Unselect();
  m_Tab.SetCurSel(0);
  m_Queries.ShowWindow(SW_HIDE);
  m_Groups.ShowWindow(SW_HIDE);
  m_Categories.ShowWindow(SW_SHOW);
  FireModeChanged(0);
}
//--------------------------------------------------------------------------------------


text:
/* tslint:disable:no-unused-variable */

/*!
 * Dynamic Modal Component Test
 *
 * Copyright(c) Exequiel Ceasar Navarrete <esnavarrete1@up.edu.ph>
 * Licensed under MIT
 */

import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { ComponentFactoryResolver, DebugElement } from '@angular/core';
import { ModalDirective } from 'ng2-bootstrap/modal';
import { PdfViewerComponent } from 'ng2-pdf-viewer';

import { SpawnModalService } from '../spawn-modal.service';

import { AlertModalComponent } from '../alert-modal/alert-modal.component';
import { BaseModalComponent } from '../base-modal/base-modal.component';
import { ChartModalComponent } from '../chart-modal/chart-modal.component';
import { DynamicModalComponent } from './dynamic-modal.component';
import { PdfPreviewModalComponent } from '../pdf-preview-modal/pdf-preview-modal.component';

describe('Component: DynamicModal', () => {
  let component: DynamicModalComponent;
  let fixture: ComponentFixture<DynamicModalComponent>;

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [
        AlertModalComponent,
        BaseModalComponent,
        ChartModalComponent,
        DynamicModalComponent,
        ModalDirective,
        PdfPreviewModalComponent,
        PdfViewerComponent
      ],
      providers: [
        SpawnModalService,
        ComponentFactoryResolver
      ]
    })
    .compileComponents();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(DynamicModalComponent);
    component = fixture.componentInstance;
    fixture.detectChanges();
  });

  it('should create the component', () => {
    expect(component).toBeTruthy();
  });

});


text:
Beginning Management for Hackers

## Description:
It may be considered the downfall of any serious developer, but becoming a manager happens to the best of us.  As a current lead developer and previous VP of Engineering, I'll talk about the ups, downs, and hacks of becoming a manager for the first time.

## Rough Outline:

Management happens
lead dev
still code

Managing your Time

Managing People

Powers of persuasion

## Audience Level:
Intermediate Rails Devs