<commit_before>/* eslint-disable no-await-in-loop */
import {
  getOAuthOctokit,
  getTokenOctokit,
  getInstallationOctokit,
} from "@argos-ci/github";
import {
  Installation,
  Organization,
  Repository,
  User,
  UserOrganizationRight,
  UserRepositoryRight,
  UserInstallationRight,
  InstallationRepositoryRight,
} from "@argos-ci/database/models";
import config from "@argos-ci/config";

export async function getOrCreateInstallation(payload) {
  const installation = await Installation.query()
    .where({ githubId: payload.githubId })
    .first();

  if (installation) return installation;
  return Installation.query().insertAndFetch(payload);
}

async function checkAccessTokenValidity(accessToken) {
  const oauthOctokit = getOAuthOctokit();
  try {
    await oauthOctokit.apps.checkToken({
      access_token: accessToken,
      client_id: config.get("github.clientId"),
    });
  } catch (error) {
    if (error.status === 404) {
      return false;
    }

    throw error;
  }

  return true;
}

const OWNER_ORGANIZATION = "Organization";
const OWNER_USER = "User";

export class GitHubSynchronizer {
  constructor(synchronization) {
    this.synchronization = synchronization;
    this.repositories = [];
    this.organizationIds = [];
  }

  async synchronizeAppRepositories(installationId) {
    const options =
      this.octokit.apps.listReposAccessibleToInstallation.endpoint.DEFAULTS;
    const githubRepositories = await this.octokit.paginate(options);
    const { repositories, organizations } = await this.synchronizeRepositories(
      githubRepositories
    );

    await this.synchronizeInstallationRepositoryRights(
      repositories,
      installationId
    );

    return { repositories, organizations };
  }

  async synchronizeUserInstallationRepositories(installation) {
    const options =
      this.octokit.apps.listInstallationReposForAuthenticatedUser.endpoint.merge(
        { installation_id: installation.githubId }
      );
    const githubRepositories = await this.octokit.paginate(options);
    const { repositories, organizations } = await this.synchronizeRepositories(
      githubRepositories
    );

    await this.synchronizeInstallationRepositoryRights(
      repositories,
      installation.id
    );

    return { repositories, organizations };
  }

  async synchronizeRepositories(githubRepositories) {
    const [
      {
        owners: organizations,
        ownerIdByRepositoryId: organizationIdByRepositoryId,
      },
      { ownerIdByRepositoryId: userIdByRepositoryId },
    ] = await Promise.all([
      this.synchronizeOwners(githubRepositories, OWNER_ORGANIZATION),
      this.synchronizeOwners(githubRepositories, OWNER_USER),
    ]);

    const repositories = await Promise.all(
      githubRepositories.map(async (githubRepository) => {
        const data = {
          githubId: githubRepository.id,
          name: githubRepository.name,
          organizationId:
            organizationIdByRepositoryId[githubRepository.id] ?? null,
          userId: userIdByRepositoryId[githubRepository.id] ?? null,
          private: githubRepository.private,
        };

        let [repository] = await Repository.query().where({
          githubId: githubRepository.id,
        });

        if (repository) {
          await repository.$query().patchAndFetch(data);
        } else {
          repository = await Repository.query().insert({
            ...data,
            enabled: false,
            baselineBranch: "master",
          });
        }

        return repository;
      })
    );

    return { repositories, organizations };
  }

  async synchronizeOwners(githubRepositories, type) {
    const githubOwners = githubRepositories.reduce(
      (githubOwners, githubRepository) => {
        if (githubRepository.owner.type !== type) {
          return githubOwners;
        }

        let githubOwner = githubOwners.find(
          ({ id }) => id === githubRepository.owner.id
        );

        if (!githubOwner) {
          githubOwner = githubRepository.owner;
          githubOwners.push(githubRepository.owner);
        }

        return githubOwners;
      },
      []
    );

    let owners;

    switch (type) {
      case OWNER_ORGANIZATION:
        owners = await Promise.all(
          githubOwners.map((githubOwner) =>
            this.synchronizeOrganization(githubOwner)
          )
        );
        break;
      case OWNER_USER:
        owners = await Promise.all(
          githubOwners.map((githubOwner) => this.synchronizeUser(githubOwner))
        );
        break;
      default:
        throw new Error(`Unsupported type ${type}`);
    }

    return {
      owners,
      ownerIdByRepositoryId: githubRepositories.reduce(
        (ownerIdByRepositoryId, githubRepository) => {
          if (githubRepository.owner.type === type) {
            ownerIdByRepositoryId[githubRepository.id] = owners.find(
              (owner) => owner.githubId === githubRepository.owner.id
            ).id;
          }

          return ownerIdByRepositoryId;
        },
        {}
      ),
    };
  }

  // eslint-disable-next-line class-methods-use-this
  async synchronizeOrganization(githubOrganization) {
    const organizationData = await this.octokit.orgs.get({
      org: githubOrganization.login,
    });
    githubOrganization = organizationData.data;
    let [organization] = await Organization.query().where({
      githubId: githubOrganization.id,
    });
    const data = {
      githubId: githubOrganization.id,
      name: githubOrganization.name,
      login: githubOrganization.login,
    };

    if (organization) {
      await organization.$query().patchAndFetch(data);
    } else {
      organization = await Organization.query().insert(data);
    }

    return organization;
  }

  // eslint-disable-next-line class-methods-use-this
  async synchronizeUser(githubUser) {
    const data = { githubId: githubUser.id, login: githubUser.login };
    let user = await User.query().where({ githubId: githubUser.id }).first();

    if (user) {
      await user.$query().patchAndFetch(data);
    } else {
      user = await User.query().insert(data);
    }

    return user;
  }

  async synchronizeInstallationRepositoryRights(repositories, installationId) {
    const installationRepositoryRights =
      await InstallationRepositoryRight.query().where({
        installationId,
      });

    await Promise.all(
      repositories.map(async (repository) => {
        const hasRights = installationRepositoryRights.some(
          ({ repositoryId }) => repositoryId === repository.id
        );

        if (!hasRights) {
          await InstallationRepositoryRight.query().insert({
            installationId,
            repositoryId: repository.id,
          });
        }
      })
    );

    await Promise.all(
      installationRepositoryRights.map(async (installationRepositoryRight) => {
        const repositoryStillExists = repositories.find(
          ({ id }) => id === installationRepositoryRight.repositoryId
        );

        if (!repositoryStillExists) {
          await installationRepositoryRight.$query().delete();
        }
      })
    );
  }

  async synchronizeRepositoryRights(repositories, userId) {
    const userRepositoryRights = await UserRepositoryRight.query().where({
      userId,
    });

    await Promise.all(
      repositories.map(async (repository) => {
        const hasRights = userRepositoryRights.some(
          ({ repositoryId }) => repositoryId === repository.id
        );

        if (!hasRights) {
          await UserRepositoryRight.query().insert({
            userId,
            repositoryId: repository.id,
          });
        }
      })
    );

    await Promise.all(
      userRepositoryRights.map(async (userRepositoryRight) => {
        const repositoryStillExists = repositories.find(
          ({ id }) => id === userRepositoryRight.repositoryId
        );

        if (!repositoryStillExists) {
          await userRepositoryRight.$query().delete();
        }
      })
    );
  }

  async synchronizeOrganizationRights(organizations, userId) {
    const userOrganizationRights = await UserOrganizationRight.query().where({
      userId,
    });

    await Promise.all(
      organizations.map(async (organization) => {
        const hasRights = userOrganizationRights.some(
          ({ organizationId }) => organizationId === organization.id
        );

        if (!hasRights) {
          await UserOrganizationRight.query().insert({
            userId,
            organizationId: organization.id,
          });
        }
      })
    );

    await Promise.all(
      userOrganizationRights.map(async (userOrganizationRight) => {
        const organizationStillExists = organizations.find(
          ({ id }) => id === userOrganizationRight.organizationId
        );

        if (!organizationStillExists) {
          await userOrganizationRight.$query().delete();
        }
      })
    );
  }

  async synchronizeUserInstallations() {
    const options =
      this.octokit.apps.listInstallationsForAuthenticatedUser.endpoint.DEFAULTS;
    const githubInstallations = await this.octokit.paginate(options);

    return Promise.all(
      githubInstallations.map(async (githubInstallation) => {
        return getOrCreateInstallation({
          githubId: githubInstallation.id,
          deleted: false,
        });
      })
    );
  }

  async synchronizeUserInstallationRights(installations, userId) {
    const userInstallationRights = await UserInstallationRight.query().where({
      userId,
    });

    await Promise.all(
      installations.map(async (installation) => {
        const exists = userInstallationRights.some(
          ({ installationId }) => installationId === installation.id
        );

        if (!exists) {
          await UserInstallationRight.query().insertAndFetch({
            userId,
            installationId: installation.id,
          });
        }
      })
    );

    await Promise.all(
      userInstallationRights.map(async (userInstallationRight) => {
        const installationStillExists = installations.find(
          ({ id }) => id === userInstallationRight.installationId
        );

        if (!installationStillExists) {
          await userInstallationRight.$query().delete();
        }
      })
    );

    return installations;
  }

  async synchronize() {
    this.synchronization = await this.synchronization.$query();

    switch (this.synchronization.type) {
      case "installation":
        return this.synchronizeFromInstallation(
          this.synchronization.installationId
        );
      case "user":
        return this.synchronizeFromUser(this.synchronization.userId);
      default:
        throw new Error(
          `Unknown synchronization type "${this.synchronization.type}"`
        );
    }
  }

  async synchronizeFromInstallation(installationId) {
    const installation = await Installation.query()
      .findById(installationId)
      .withGraphFetched("users");

    if (installation.deleted) {
      await Promise.all(
        installation.users.map(async (user) =>
          this.synchronizeFromUser(user.id)
        )
      );
      await this.synchronizeInstallationRepositoryRights([], installationId);
      return;
    }

    const octokit = await getInstallationOctokit(installation.githubId);

    // If we don't get an octokit, then the installation has been removed
    // we deleted the installation
    if (!octokit) {
      await installation.$query().patch({ deleted: true });
      return;
    }

    this.octokit = octokit;

    await this.synchronizeAppRepositories(installationId);

    await Promise.all(
      installation.users.map(async (user) => this.synchronizeFromUser(user.id))
    );
  }

  async synchronizeFromUser(userId) {
    const user = await User.query().findById(userId);
    const tokenValid = await checkAccessTokenValidity(user.accessToken);

    if (!tokenValid) {
      await this.synchronizeUserInstallationRights([], userId);
      await Promise.all([
        this.synchronizeRepositoryRights([], userId),
        this.synchronizeOrganizationRights([], userId),
      ]);
      return;
    }

    this.octokit = getTokenOctokit(user.accessToken);

    const installations = await this.synchronizeUserInstallations(userId);

    await this.synchronizeUserInstallationRights(installations, userId);

    const results = await Promise.all(
      installations.map((installation) =>
        this.synchronizeUserInstallationRepositories(installation)
      )
    );

    const { repositories, organizations } = results.reduce(
      (all, result) => {
        all.repositories = [...all.repositories, ...result.repositories];
        all.organizations = [...all.organizations, ...result.organizations];
        return all;
      },
      { repositories: [], organizations: [] }
    );

    await Promise.all([
      this.synchronizeRepositoryRights(repositories, userId),
      this.synchronizeOrganizationRights(organizations, userId),
    ]);
  }
}
<commit_msg>chore: remove double ??<commit_after>/* eslint-disable no-await-in-loop */
import {
  getOAuthOctokit,
  getTokenOctokit,
  getInstallationOctokit,
} from "@argos-ci/github";
import {
  Installation,
  Organization,
  Repository,
  User,
  UserOrganizationRight,
  UserRepositoryRight,
  UserInstallationRight,
  InstallationRepositoryRight,
} from "@argos-ci/database/models";
import config from "@argos-ci/config";

export async function getOrCreateInstallation(payload) {
  const installation = await Installation.query()
    .where({ githubId: payload.githubId })
    .first();

  if (installation) return installation;
  return Installation.query().insertAndFetch(payload);
}

async function checkAccessTokenValidity(accessToken) {
  const oauthOctokit = getOAuthOctokit();
  try {
    await oauthOctokit.apps.checkToken({
      access_token: accessToken,
      client_id: config.get("github.clientId"),
    });
  } catch (error) {
    if (error.status === 404) {
      return false;
    }

    throw error;
  }

  return true;
}

const OWNER_ORGANIZATION = "Organization";
const OWNER_USER = "User";

export class GitHubSynchronizer {
  constructor(synchronization) {
    this.synchronization = synchronization;
    this.repositories = [];
    this.organizationIds = [];
  }

  async synchronizeAppRepositories(installationId) {
    const options =
      this.octokit.apps.listReposAccessibleToInstallation.endpoint.DEFAULTS;
    const githubRepositories = await this.octokit.paginate(options);
    const { repositories, organizations } = await this.synchronizeRepositories(
      githubRepositories
    );

    await this.synchronizeInstallationRepositoryRights(
      repositories,
      installationId
    );

    return { repositories, organizations };
  }

  async synchronizeUserInstallationRepositories(installation) {
    const options =
      this.octokit.apps.listInstallationReposForAuthenticatedUser.endpoint.merge(
        { installation_id: installation.githubId }
      );
    const githubRepositories = await this.octokit.paginate(options);
    const { repositories, organizations } = await this.synchronizeRepositories(
      githubRepositories
    );

    await this.synchronizeInstallationRepositoryRights(
      repositories,
      installation.id
    );

    return { repositories, organizations };
  }

  async synchronizeRepositories(githubRepositories) {
    const [
      {
        owners: organizations,
        ownerIdByRepositoryId: organizationIdByRepositoryId,
      },
      { ownerIdByRepositoryId: userIdByRepositoryId },
    ] = await Promise.all([
      this.synchronizeOwners(githubRepositories, OWNER_ORGANIZATION),
      this.synchronizeOwners(githubRepositories, OWNER_USER),
    ]);

    const repositories = await Promise.all(
      githubRepositories.map(async (githubRepository) => {
        const data = {
          githubId: githubRepository.id,
          name: githubRepository.name,
          organizationId:
            organizationIdByRepositoryId[githubRepository.id] || null,
          userId: userIdByRepositoryId[githubRepository.id] || null,
          private: githubRepository.private,
        };

        let [repository] = await Repository.query().where({
          githubId: githubRepository.id,
        });

        if (repository) {
          await repository.$query().patchAndFetch(data);
        } else {
          repository = await Repository.query().insert({
            ...data,
            enabled: false,
            baselineBranch: "master",
          });
        }

        return repository;
      })
    );

    return { repositories, organizations };
  }

  async synchronizeOwners(githubRepositories, type) {
    const githubOwners = githubRepositories.reduce(
      (githubOwners, githubRepository) => {
        if (githubRepository.owner.type !== type) {
          return githubOwners;
        }

        let githubOwner = githubOwners.find(
          ({ id }) => id === githubRepository.owner.id
        );

        if (!githubOwner) {
          githubOwner = githubRepository.owner;
          githubOwners.push(githubRepository.owner);
        }

        return githubOwners;
      },
      []
    );

    let owners;

    switch (type) {
      case OWNER_ORGANIZATION:
        owners = await Promise.all(
          githubOwners.map((githubOwner) =>
            this.synchronizeOrganization(githubOwner)
          )
        );
        break;
      case OWNER_USER:
        owners = await Promise.all(
          githubOwners.map((githubOwner) => this.synchronizeUser(githubOwner))
        );
        break;
      default:
        throw new Error(`Unsupported type ${type}`);
    }

    return {
      owners,
      ownerIdByRepositoryId: githubRepositories.reduce(
        (ownerIdByRepositoryId, githubRepository) => {
          if (githubRepository.owner.type === type) {
            ownerIdByRepositoryId[githubRepository.id] = owners.find(
              (owner) => owner.githubId === githubRepository.owner.id
            ).id;
          }

          return ownerIdByRepositoryId;
        },
        {}
      ),
    };
  }

  // eslint-disable-next-line class-methods-use-this
  async synchronizeOrganization(githubOrganization) {
    const organizationData = await this.octokit.orgs.get({
      org: githubOrganization.login,
    });
    githubOrganization = organizationData.data;
    let [organization] = await Organization.query().where({
      githubId: githubOrganization.id,
    });
    const data = {
      githubId: githubOrganization.id,
      name: githubOrganization.name,
      login: githubOrganization.login,
    };

    if (organization) {
      await organization.$query().patchAndFetch(data);
    } else {
      organization = await Organization.query().insert(data);
    }

    return organization;
  }

  // eslint-disable-next-line class-methods-use-this
  async synchronizeUser(githubUser) {
    const data = { githubId: githubUser.id, login: githubUser.login };
    let user = await User.query().where({ githubId: githubUser.id }).first();

    if (user) {
      await user.$query().patchAndFetch(data);
    } else {
      user = await User.query().insert(data);
    }

    return user;
  }

  async synchronizeInstallationRepositoryRights(repositories, installationId) {
    const installationRepositoryRights =
      await InstallationRepositoryRight.query().where({
        installationId,
      });

    await Promise.all(
      repositories.map(async (repository) => {
        const hasRights = installationRepositoryRights.some(
          ({ repositoryId }) => repositoryId === repository.id
        );

        if (!hasRights) {
          await InstallationRepositoryRight.query().insert({
            installationId,
            repositoryId: repository.id,
          });
        }
      })
    );

    await Promise.all(
      installationRepositoryRights.map(async (installationRepositoryRight) => {
        const repositoryStillExists = repositories.find(
          ({ id }) => id === installationRepositoryRight.repositoryId
        );

        if (!repositoryStillExists) {
          await installationRepositoryRight.$query().delete();
        }
      })
    );
  }

  async synchronizeRepositoryRights(repositories, userId) {
    const userRepositoryRights = await UserRepositoryRight.query().where({
      userId,
    });

    await Promise.all(
      repositories.map(async (repository) => {
        const hasRights = userRepositoryRights.some(
          ({ repositoryId }) => repositoryId === repository.id
        );

        if (!hasRights) {
          await UserRepositoryRight.query().insert({
            userId,
            repositoryId: repository.id,
          });
        }
      })
    );

    await Promise.all(
      userRepositoryRights.map(async (userRepositoryRight) => {
        const repositoryStillExists = repositories.find(
          ({ id }) => id === userRepositoryRight.repositoryId
        );

        if (!repositoryStillExists) {
          await userRepositoryRight.$query().delete();
        }
      })
    );
  }

  async synchronizeOrganizationRights(organizations, userId) {
    const userOrganizationRights = await UserOrganizationRight.query().where({
      userId,
    });

    await Promise.all(
      organizations.map(async (organization) => {
        const hasRights = userOrganizationRights.some(
          ({ organizationId }) => organizationId === organization.id
        );

        if (!hasRights) {
          await UserOrganizationRight.query().insert({
            userId,
            organizationId: organization.id,
          });
        }
      })
    );

    await Promise.all(
      userOrganizationRights.map(async (userOrganizationRight) => {
        const organizationStillExists = organizations.find(
          ({ id }) => id === userOrganizationRight.organizationId
        );

        if (!organizationStillExists) {
          await userOrganizationRight.$query().delete();
        }
      })
    );
  }

  async synchronizeUserInstallations() {
    const options =
      this.octokit.apps.listInstallationsForAuthenticatedUser.endpoint.DEFAULTS;
    const githubInstallations = await this.octokit.paginate(options);

    return Promise.all(
      githubInstallations.map(async (githubInstallation) => {
        return getOrCreateInstallation({
          githubId: githubInstallation.id,
          deleted: false,
        });
      })
    );
  }

  async synchronizeUserInstallationRights(installations, userId) {
    const userInstallationRights = await UserInstallationRight.query().where({
      userId,
    });

    await Promise.all(
      installations.map(async (installation) => {
        const exists = userInstallationRights.some(
          ({ installationId }) => installationId === installation.id
        );

        if (!exists) {
          await UserInstallationRight.query().insertAndFetch({
            userId,
            installationId: installation.id,
          });
        }
      })
    );

    await Promise.all(
      userInstallationRights.map(async (userInstallationRight) => {
        const installationStillExists = installations.find(
          ({ id }) => id === userInstallationRight.installationId
        );

        if (!installationStillExists) {
          await userInstallationRight.$query().delete();
        }
      })
    );

    return installations;
  }

  async synchronize() {
    this.synchronization = await this.synchronization.$query();

    switch (this.synchronization.type) {
      case "installation":
        return this.synchronizeFromInstallation(
          this.synchronization.installationId
        );
      case "user":
        return this.synchronizeFromUser(this.synchronization.userId);
      default:
        throw new Error(
          `Unknown synchronization type "${this.synchronization.type}"`
        );
    }
  }

  async synchronizeFromInstallation(installationId) {
    const installation = await Installation.query()
      .findById(installationId)
      .withGraphFetched("users");

    if (installation.deleted) {
      await Promise.all(
        installation.users.map(async (user) =>
          this.synchronizeFromUser(user.id)
        )
      );
      await this.synchronizeInstallationRepositoryRights([], installationId);
      return;
    }

    const octokit = await getInstallationOctokit(installation.githubId);

    // If we don't get an octokit, then the installation has been removed
    // we deleted the installation
    if (!octokit) {
      await installation.$query().patch({ deleted: true });
      return;
    }

    this.octokit = octokit;

    await this.synchronizeAppRepositories(installationId);

    await Promise.all(
      installation.users.map(async (user) => this.synchronizeFromUser(user.id))
    );
  }

  async synchronizeFromUser(userId) {
    const user = await User.query().findById(userId);
    const tokenValid = await checkAccessTokenValidity(user.accessToken);

    if (!tokenValid) {
      await this.synchronizeUserInstallationRights([], userId);
      await Promise.all([
        this.synchronizeRepositoryRights([], userId),
        this.synchronizeOrganizationRights([], userId),
      ]);
      return;
    }

    this.octokit = getTokenOctokit(user.accessToken);

    const installations = await this.synchronizeUserInstallations(userId);

    await this.synchronizeUserInstallationRights(installations, userId);

    const results = await Promise.all(
      installations.map((installation) =>
        this.synchronizeUserInstallationRepositories(installation)
      )
    );

    const { repositories, organizations } = results.reduce(
      (all, result) => {
        all.repositories = [...all.repositories, ...result.repositories];
        all.organizations = [...all.organizations, ...result.organizations];
        return all;
      },
      { repositories: [], organizations: [] }
    );

    await Promise.all([
      this.synchronizeRepositoryRights(repositories, userId),
      this.synchronizeOrganizationRights(organizations, userId),
    ]);
  }
}
<|endoftext|>


<commit_before>var fs = require('fs');
var Handlebars = require("handlebars");
var HandlebarHelper = require(_path.content + "/module/imboard/js/handlebars-helper.js");

var DataBindModule = function()
{
	if(DataBindModule.caller != DataBindModule.getInstance)
		throw Error('this DataBindModule cannot be instanciated');

	this.modules = {};

	this.loadCustomHelper();
};

DataBindModule.prototype.loadCustomHelper = function()
{
	var path = _path.content + "/frame/" + _config.frame + "/properties/handlebars/";

	try
	{
		var result = fs.readdirSync(path);
		for(var i=0; i<result.length; i++)
		{
			require(path + result[i]);
		}
	}
	catch(err)
	{
//		_log.error(err.stack);
	}
};

DataBindModule.prototype.databind = function($, el, req, callback)
{
	var list = $(el).find("*[data-bind]");
	this.compile($, list, req, callback, 0);
};

DataBindModule.prototype.getTemplate = function($, el)
{
	var html = "";
	try
	{
		var templateId = $(el).attr('data-template-id');
		if(templateId)
		{
			var template = $("#" + templateId);
			html = template.html();

			if(template.attr("data-precompile") == "true")
			{
				//프리컴파일형식으로 만들어두자?
			}
			else
			{
				template.remove();
			}
		}
		else
		{
			if($(el).attr("data-precompile") == "true")
			{

			}

			html = $(el).html().replace(/\\"/gi, "\"");
		}

		$(el).removeAttr("data-template-id");

		if(!html)
			html = "
Empty template!
";

		var matchs = html.match(/{{[^}]*}}/gi);
		if(matchs)
		{
			for(var i=0; i<matchs.length; i++)
			{
				var replaceString = matchs[i].replace(/"/gi, "\"");
				html = html.replace(matchs[i], replaceString);
			}
		}

		return Handlebars.compile(html);
	}
	catch(err)
	{
		_log.error(err.stack);
	}

	return null;
};

DataBindModule.prototype.getParameters = function($, el)
{
	var param = {};
	var value = "";
	try
	{
		value = $(el).attr("data-param");
		if(value != null)
		{
			param = JSON.parse(value);
			if(param == null)
				param = {};
		}

		$(el).removeAttr("data-param");
	}
	catch(err)
	{
		_log.error(err.stack);
		$(el).html(" ParseException : " + value + "

" + err.stack + "
");
		param = null;
	}

	return param;
};

DataBindModule.prototype.compile = function($, list, req, callback, index)
{
	var that = this;
	if(index >= list.length)
	{
		callback($.html());
	}
	else
	{
		var el = list[index];

		this.databind($, el, req, function() // el의 innerHTML로 템플릿이 작성되어있는경우 data-bind가 발견될 수 있다. 그럼 끝까지 파고들어서 맨 마지막 data-bind부터 실행함.
		{
			//마지막 data-bind el의 innerHTML에 data-bind가 없는 경우 아래 코드가 수행됨

			var name = $(el).attr("data-bind");
			$(el).removeAttr("data-bind");

			if(that.modules.hasOwnProperty(name)) // data-bind 모듈체크 후
			{
				var param = that.getParameters($, el);
				if(param == null)
				{
					that.compile($, list, req, callback, index+1); // 파라미터 가져오는도중 파싱에러가 발생하면 다음 시블링의 data-bind로 넘어간다.
				}
				else
				{
					try
					{
						that.modules[name].call(that, $, el, param, req, function() // 정상적인 파라미터를 얻은경우 모듈 호출.
						{
							that.databind($, el, req, function() //script로 템플릿이 작성된경우는 위에서 검출이 안된다. 따라서 data-bind 후 템플릿이 실제로 innerHTML로 만들어졌을 때 data-bind가 또 있는지 체크하고 수행함
							{
								that.compile($, list, req, callback, index+1); //끝나면 다음 시블링 data-bind로 넘어감.
							});
						});
					}
					catch(err)
					{
						//모듈 호출시 오류 발생하는경우
						_log.error(err.stack);

						//다음으로 넘어감
						that.databind($, el, req, function()
						{
							that.compile($, list, req, callback, index+1); //끝나면 다음 시블링 data-bind로 넘어감.
						});
					}
				}
			}
			else
			{
				$(el).attr("data-bind-description", "module not found"); // 모듈이 없는경우 알려주기 위해..
				that.compile($, list, req, callback, index+1);
			}
		});
	}
};

DataBindModule.prototype.addModule = function(key, f)
{
	this.modules[key] = f;
};

DataBindModule.instance = null;

DataBindModule.getInstance = function()
{
	if(this.instance == null)
		this.instance = new DataBindModule();

	return this.instance;
};

module.exports = DataBindModule.getInstance();<commit_msg>Databind 모듈이 없는경우 html로 오류 보여주도록 수정<commit_after>var fs = require('fs');
var Handlebars = require("handlebars");
var HandlebarHelper = require(_path.content + "/module/imboard/js/handlebars-helper.js");

var DataBindModule = function()
{
	if(DataBindModule.caller != DataBindModule.getInstance)
		throw Error('this DataBindModule cannot be instanciated');

	this.modules = {};

	this.loadCustomHelper();
};

DataBindModule.prototype.loadCustomHelper = function()
{
	var path = _path.content + "/frame/" + _config.frame + "/properties/handlebars/";

	try
	{
		var result = fs.readdirSync(path);
		for(var i=0; i<result.length; i++)
		{
			require(path + result[i]);
		}
	}
	catch(err)
	{
//		_log.error(err.stack);
	}
};

DataBindModule.prototype.databind = function($, el, req, callback)
{
	var list = $(el).find("*[data-bind]");
	this.compile($, list, req, callback, 0);
};

DataBindModule.prototype.getTemplate = function($, el)
{
	var html = "";
	try
	{
		var templateId = $(el).attr('data-template-id');
		if(templateId)
		{
			var template = $("#" + templateId);
			html = template.html();

			if(template.attr("data-precompile") == "true")
			{
				//프리컴파일형식으로 만들어두자?
			}
			else
			{
				template.remove();
			}
		}
		else
		{
			if($(el).attr("data-precompile") == "true")
			{

			}

			html = $(el).html().replace(/\\"/gi, "\"");
		}

		$(el).removeAttr("data-template-id");

		if(!html)
			html = "
Empty template!
";

		var matchs = html.match(/{{[^}]*}}/gi);
		if(matchs)
		{
			for(var i=0; i<matchs.length; i++)
			{
				var replaceString = matchs[i].replace(/"/gi, "\"");
				html = html.replace(matchs[i], replaceString);
			}
		}

		return Handlebars.compile(html);
	}
	catch(err)
	{
		_log.error(err.stack);
	}

	return null;
};

DataBindModule.prototype.getParameters = function($, el)
{
	var param = {};
	var value = "";
	try
	{
		value = $(el).attr("data-param");
		if(value != null)
		{
			param = JSON.parse(value);
			if(param == null)
				param = {};
		}

		$(el).removeAttr("data-param");
	}
	catch(err)
	{
		_log.error(err.stack);
		$(el).html(" ParseException : " + value + "

" + err.stack + "
");
		param = null;
	}

	return param;
};

DataBindModule.prototype.compile = function($, list, req, callback, index)
{
	var that = this;
	if(index >= list.length)
	{
		callback($.html());
	}
	else
	{
		var el = list[index];

		this.databind($, el, req, function() // el의 innerHTML로 템플릿이 작성되어있는경우 data-bind가 발견될 수 있다. 그럼 끝까지 파고들어서 맨 마지막 data-bind부터 실행함.
		{
			//마지막 data-bind el의 innerHTML에 data-bind가 없는 경우 아래 코드가 수행됨

			var name = $(el).attr("data-bind");
			$(el).removeAttr("data-bind");

			if(that.modules.hasOwnProperty(name)) // data-bind 모듈체크 후
			{
				var param = that.getParameters($, el);
				if(param == null)
				{
					that.compile($, list, req, callback, index+1); // 파라미터 가져오는도중 파싱에러가 발생하면 다음 시블링의 data-bind로 넘어간다.
				}
				else
				{
					try
					{
						that.modules[name].call(that, $, el, param, req, function() // 정상적인 파라미터를 얻은경우 모듈 호출.
						{
							that.databind($, el, req, function() //script로 템플릿이 작성된경우는 위에서 검출이 안된다. 따라서 data-bind 후 템플릿이 실제로 innerHTML로 만들어졌을 때 data-bind가 또 있는지 체크하고 수행함
							{
								that.compile($, list, req, callback, index+1); //끝나면 다음 시블링 data-bind로 넘어감.
							});
						});
					}
					catch(err)
					{
						//모듈 호출시 오류 발생하는경우
						_log.error(err.stack);

						//다음으로 넘어감
						that.databind($, el, req, function()
						{
							that.compile($, list, req, callback, index+1); //끝나면 다음 시블링 data-bind로 넘어감.
						});
					}
				}
			}
			else
			{
				$(el).removeAttr("data-param").removeAttr("data-template-id");
				$(el).html(" ModuleNotFoundException : " + name + ""); // 모듈이 없는경우 알려주기 위해..
				that.compile($, list, req, callback, index+1);
			}
		});
	}
};

DataBindModule.prototype.addModule = function(key, f)
{
	this.modules[key] = f;
};

DataBindModule.instance = null;

DataBindModule.getInstance = function()
{
	if(this.instance == null)
		this.instance = new DataBindModule();

	return this.instance;
};

module.exports = DataBindModule.getInstance();<|endoftext|>


<commit_before>var display;
var canvas;
var context;
var overlay;
var overlayContext;
var underlay;
var underlayContext;
var scale;
var scaleContext;
var buckets = [];
var maxColumns = 96;
var maxRows = 10;
var gridSize = 30;
var gutterSize = 14;

var rightLimit = 0;

function initCanvas() {
	display = document.getElementById("display");

	canvas = document.getElementById("canvas");
	context = canvas.getContext("2d");
	overlay = document.getElementById("overlay");
	overlayContext = overlay.getContext("2d");

	underlay = document.getElementById("underlay");
	underlayContext = underlay.getContext("2d");

	scale = document.getElementById("scale");
	scaleContext = scale.getContext("2d");

	rightLimit = (maxColumns * gridSize) - canvas.width;
}

function clearCanvas() {
	canvas.width = canvas.width;
}

function clearOverlay() {
	overlay.width = overlay.width;
}

function clearUnderlay() {
	underlay.width = underlay.width;
}

function clearScale() {
	scale.width = scale.width;
}

var sessionId = null;

function createSession(cb) {
	var handleSessionId = function(data, status, req) {
		var location = req.getResponseHeader('Location');
		var parts = location.split("/");
		var sessionID = parts[parts.length - 1];
		sessionId = sessionID;

		cb();
	};
	$.post(API_BASE + '/diffs/sessions', {}, handleSessionId, "json");
}

var startTime, endTime;
var bucketSize = 3600;

var swimlaneLabels = [];
function loadTestData() {
	buckets = [];
	for (var i = 0; i < maxRows; i++) {
		var row = [];
		for (var j = 0; j < maxColumns; j++) {
			row[j] = 0;
		}
		buckets[i] = row;
	}

	endTime = new Date();
	var now = endTime.formatString("YYYY0MM0DDT0hh0mm0ssZ");

	startTime = new Date(endTime - (3600 * maxColumns * 1000));
	var dayBeforeNow = startTime.formatString("YYYY0MM0DDT0hh0mm0ssZ");

	$.get("rest/diffs/sessions/" + sessionId + "/zoom?range-start=" + dayBeforeNow + "&range-end=" + now + "&bucketing=3600", function(data) {
		var indexer = 0;

		for (var pair in data) {
			swimlaneLabels[indexer] = pair;
			for (var x = 0; x < data[pair].length; x++) {
				buckets[indexer][x] = data[pair][x];
			}
			indexer++;
		}
		clearEverything();
		o_x = -1 * rightLimit;
		context.translate(o_x, o_y);
		scaleContext.translate(o_x, o_y);
		drawGrid();
	});
}

var timeout;
var polling = true;
function startPolling() {
	polling = true;
	clearTimeout(timeout);
	createSession(function() {
		loadTestData();
	});
	timeout = window.setTimeout(startPolling, 5000);
	$("#polling").text("Stop polling");
}

function stopPolling() {
	polling = false;
	clearTimeout(timeout);
	$("#polling").text("Start polling");
}

function dashedLine(ctx, x1, y1, x2, y2, dashLen) {
	if (dashLen == undefined) dashLen = 2;

	ctx.beginPath();
	ctx.moveTo(x1, y1);

	var dX = x2 - x1;
	var dY = y2 - y1;
	var dashes = Math.floor(Math.sqrt(dX * dX + dY * dY) / dashLen);
	var dashX = dX / dashes;
	var dashY = dY / dashes;

	var q = 0;
	while (q++ < dashes) {
		x1 += dashX;
		y1 += dashY;
		if (q % 2 == 0) {
			ctx.moveTo(x1, y1);
		}
		else {
			ctx.lineTo(x1, y1);
		}
	}
	if (q % 2 == 0) {
		ctx.moveTo(x1, y1);
	}
	else {
		ctx.lineTo(x1, y1);
	}

	ctx.stroke();
	ctx.closePath();
}

var selected;
function drawCircle(i, j) {
	var cell = coordsToPosition({"x":i, "y":j});
	if (cell.column < maxColumns && cell.row < maxRows) {
		var cell_x = i + Math.floor(gridSize / 2);
		var cell_y = j + gutterSize + Math.floor(gridSize / 2);
		var size = limit(buckets[cell.row][cell.column], Math.floor((gridSize - 1) / 2));
		if (size.limited) {
			context.lineWidth = 2;
		}
		else {
			context.lineWidth = 1;
		}
		context.strokeStyle = "black";
		context.fillStyle = "white";
		context.beginPath();
		context.arc(cell_x, cell_y, size.value, 0, Math.PI * 2, false);
		context.closePath();
		context.stroke();
		context.fill();
	}
}

var show_grid = false;
function drawGrid() {
	var region_width = maxColumns * gridSize;
	if (show_grid) {
		for (var x = 0.5; x < region_width; x += gridSize) {
			context.moveTo(x, 0);
			context.lineTo(x, canvas.height);
		}
		for (var y = 0.5; y < canvas.height; y += (2 * gutterSize + gridSize)) {
			context.moveTo(0, y);
			context.lineTo(region_width, y);
		}
		context.strokeStyle = "red";
		context.stroke();
	}

	var lane = 0;
	for (var s = 0.5 + (2 * gutterSize + gridSize); s < canvas.height; s += (2 * gutterSize + gridSize)) {
		dashedLine(underlayContext, 0, s, canvas.width, s, 2);
		if (swimlaneLabels[lane] != null) {
			underlayContext.font = "11px serif";
			underlayContext.fillText(swimlaneLabels[lane], 10, s - 3);
		}
		lane++;
	}

	for (var i = 0.5; i < region_width; i += gridSize) {
		for (var j = 0.5; j < canvas.height; j += (2 * gutterSize + gridSize)) {
			drawCircle(i, j);
		}
	}

	scaleContext.font = "9px sans-serif";
	for (var sc = 0; sc < maxColumns; sc++) {
		if (sc % 3 == 0) {
			var tick = new Date(startTime.getTime() + (sc * bucketSize * 1000));
			scaleContext.fillText(tick.formatString("0DD/0MM"), sc * gridSize, 10);
			scaleContext.fillText(tick.formatString("0hh:0mm"), sc * gridSize, 20);
		}
	}
}

var highlighted;
function drawOverlay() {
	if (highlighted != null && highlighted.column >= 0 && highlighted.row >= 0) {
		var value = buckets[highlighted.row][highlighted.column];
		if (value > 0) {
			var c_x = highlighted.column * gridSize;
			var c_y = (highlighted.row * (2 * gutterSize + gridSize)) + gutterSize;
			overlayContext.font = "12px sans-serif";
			overlayContext.textBaseline = "bottom";
			var width = context.measureText("" + value).width;
			overlayContext.fillText(value, c_x + Math.floor(gridSize / 2) - Math.floor(width / 2), c_y);
		}
	}
}

function limit(value, maximum) {
	if (value <= maximum) {
		return {"value":value, "limited":false};
	}
	return {"value":maximum, "limited":true};
}

var o_x = rightLimit;
var o_y = 0;
function coords(e) {
	var x;
	var y;
	if (e.pageX != undefined && e.pageY != undefined) {
		x = e.pageX;
		y = e.pageY;
	}
	else {
		x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
	}

	x -= display.offsetLeft;
	y -= display.offsetTop;

	return { "x":x, "y":y };
}

function coordsToPosition(coords) {
	return {
		"row": Math.floor(coords.y / (2 * gutterSize + gridSize)),
		"column": Math.floor((coords.x) / gridSize)
	};
}

var dragging = false;
function mouseDown(e) {
	switch (e.which) {
		case 3:
			alert("RIGHT CLICK");
			break;
		default:
			dragging = e;
			stopPolling();
			polling = false;
			var c = coords(e);
			c.x -= o_x;
			selected = coordsToPosition(c);
	}
}

function mouseUp(e) {
	dragging = false;
	polling = true;
}

function clearEverything() {
	clearCanvas();
	clearOverlay();
	clearUnderlay();
	clearScale();
}

function mouseMove(e) {
	if (dragging) {
		clearEverything()
		var m_coords = coords(e);
		var d_coords = coords(dragging);
		o_x += m_coords.x - d_coords.x;
		if (o_x > 0) {
			o_x = 0;
			//alert("This application can only show 7 days worth of data.\n\nThis restriction could be removed if you raise a change request with the Diffa development team.")
		}

		if (Math.abs(o_x) > rightLimit) {
			o_x = -1 * rightLimit;
		}
		context.translate(o_x, o_y);
		scaleContext.translate(o_x, 0);
		drawGrid();
		dragging = e;
		$("#debug").text("Offset " + o_x + " " + rightLimit);
	}
	else {
		clearOverlay();
		overlayContext.translate(o_x, o_y);
		mouseOver(e);
	}
}

function mouseOver(e) {
	var c = coords(e);
	c.x -= o_x;
	var position = coordsToPosition(c);
	if (position.row >= 0 && position.row < maxRows && position.column >= 0 && position.column < maxColumns) {
		highlighted = position;
		drawOverlay();
	}
}

function initGraph() {
	initCanvas();
	startPolling();

	$(document).mouseup(mouseUp);
	$("#display").mousedown(mouseDown);
	$(document).mousemove(mouseMove);

	$("#display").bind("contextmenu", function(e) {
		return false;
	});

	$("#polling").toggle(
		function() {
			if(polling)	{
				stopPolling();
			}
		},
		function() {
			startPolling();
		}
	);
}
<commit_msg>Slight change to session logic to prevent creation of session on every request<commit_after>var display;
var canvas;
var context;
var overlay;
var overlayContext;
var underlay;
var underlayContext;
var scale;
var scaleContext;
var buckets = [];
var maxColumns = 96;
var maxRows = 10;
var gridSize = 30;
var gutterSize = 14;

var rightLimit = 0;

function initCanvas() {
	display = document.getElementById("display");

	canvas = document.getElementById("canvas");
	context = canvas.getContext("2d");
	overlay = document.getElementById("overlay");
	overlayContext = overlay.getContext("2d");

	underlay = document.getElementById("underlay");
	underlayContext = underlay.getContext("2d");

	scale = document.getElementById("scale");
	scaleContext = scale.getContext("2d");

	rightLimit = (maxColumns * gridSize) - canvas.width;
}

function clearCanvas() {
	canvas.width = canvas.width;
}

function clearOverlay() {
	overlay.width = overlay.width;
}

function clearUnderlay() {
	underlay.width = underlay.width;
}

function clearScale() {
	scale.width = scale.width;
}

var sessionId = null;

function createSession() {
	var handleSessionId = function(data, status, req) {
		var location = req.getResponseHeader('Location');
		var parts = location.split("/");
		var sessionID = parts[parts.length - 1];
		sessionId = sessionID;
	};
	$.post(API_BASE + '/diffs/sessions', {}, handleSessionId, "json");
}

var startTime, endTime;
var bucketSize = 3600;

const TIME_FORMAT = "YYYY0MM0DDT0hh0mm0ssZ";
var swimlaneLabels = [];
function loadBuckets() {
	buckets = [];
	for (var i = 0; i < maxRows; i++) {
		var row = [];
		for (var j = 0; j < maxColumns; j++) {
			row[j] = 0;
		}
		buckets[i] = row;
	}

	endTime = new Date();

	var now = endTime.formatString(TIME_FORMAT);

	startTime = new Date(endTime - (3600 * maxColumns * 1000));
	var dayBeforeNow = startTime.formatString(TIME_FORMAT);

	$.get("rest/diffs/sessions/" + sessionId + "/zoom?range-start=" + dayBeforeNow + "&range-end=" + now + "&bucketing=3600", function(data) {
		var indexer = 0;

		for (var pair in data) {
			swimlaneLabels[indexer] = pair;
			for (var x = 0; x < data[pair].length; x++) {
				buckets[indexer][x] = data[pair][x];
			}
			indexer++;
		}
		clearEverything();
		o_x = -1 * rightLimit;
		context.translate(o_x, o_y);
		scaleContext.translate(o_x, o_y);
		drawGrid();
	});
}

function fetchData()	{
	var selectedStart = new Date(startTime.getTime() + (selected.column * bucketSize * 1000));
	var selectedEnd = new Date(selectedStart.getTime() + (bucketSize * 1000));

}

var timeout;
var polling = true;
function startPolling() {
	polling = true;
	clearTimeout(timeout);
//	createSession(function() {
		loadBuckets();
//	});
	timeout = window.setTimeout(startPolling, 5000);
	$("#polling").text("Stop polling");
}

function stopPolling() {
	polling = false;
	clearTimeout(timeout);
	$("#polling").text("Start polling");
}

function dashedLine(ctx, x1, y1, x2, y2, dashLen) {
	if (dashLen == undefined) dashLen = 2;

	ctx.beginPath();
	ctx.moveTo(x1, y1);

	var dX = x2 - x1;
	var dY = y2 - y1;
	var dashes = Math.floor(Math.sqrt(dX * dX + dY * dY) / dashLen);
	var dashX = dX / dashes;
	var dashY = dY / dashes;

	var q = 0;
	while (q++ < dashes) {
		x1 += dashX;
		y1 += dashY;
		if (q % 2 == 0) {
			ctx.moveTo(x1, y1);
		}
		else {
			ctx.lineTo(x1, y1);
		}
	}
	if (q % 2 == 0) {
		ctx.moveTo(x1, y1);
	}
	else {
		ctx.lineTo(x1, y1);
	}

	ctx.stroke();
	ctx.closePath();
}

var selected;
function drawCircle(i, j) {
	var cell = coordsToPosition({"x":i, "y":j});
	if (cell.column < maxColumns && cell.row < maxRows) {
		var cell_x = i + Math.floor(gridSize / 2);
		var cell_y = j + gutterSize + Math.floor(gridSize / 2);
		var size = limit(buckets[cell.row][cell.column], Math.floor((gridSize - 1) / 2));
		if (size.limited) {
			context.lineWidth = 2;
		}
		else {
			context.lineWidth = 1;
		}
		context.strokeStyle = "black";
		context.fillStyle = "white";
		context.beginPath();
		context.arc(cell_x, cell_y, size.value, 0, Math.PI * 2, false);
		context.closePath();
		context.stroke();
		context.fill();
	}
}

var show_grid = false;
function drawGrid() {
	var region_width = maxColumns * gridSize;
	if (show_grid) {
		for (var x = 0.5; x < region_width; x += gridSize) {
			context.moveTo(x, 0);
			context.lineTo(x, canvas.height);
		}
		for (var y = 0.5; y < canvas.height; y += (2 * gutterSize + gridSize)) {
			context.moveTo(0, y);
			context.lineTo(region_width, y);
		}
		context.strokeStyle = "red";
		context.stroke();
	}

	var lane = 0;
	for (var s = 0.5 + (2 * gutterSize + gridSize); s < canvas.height; s += (2 * gutterSize + gridSize)) {
		dashedLine(underlayContext, 0, s, canvas.width, s, 2);
		if (swimlaneLabels[lane] != null) {
			underlayContext.font = "11px serif";
			underlayContext.fillText(swimlaneLabels[lane], 10, s - 3);
		}
		lane++;
	}

	for (var i = 0.5; i < region_width; i += gridSize) {
		for (var j = 0.5; j < canvas.height; j += (2 * gutterSize + gridSize)) {
			drawCircle(i, j);
		}
	}

	scaleContext.font = "9px sans-serif";
	for (var sc = 0; sc < maxColumns; sc++) {
		if (sc % 3 == 0) {
			var tick = new Date(startTime.getTime() + (sc * bucketSize * 1000));
			scaleContext.fillText(tick.formatString("0DD/0MM"), sc * gridSize, 10);
			scaleContext.fillText(tick.formatString("0hh:0mm"), sc * gridSize, 20);
		}
	}
}

var highlighted;
function drawOverlay() {
	if (highlighted != null && highlighted.column >= 0 && highlighted.row >= 0) {
		var value = buckets[highlighted.row][highlighted.column];
		if (value > 0) {
			var c_x = highlighted.column * gridSize;
			var c_y = (highlighted.row * (2 * gutterSize + gridSize)) + gutterSize;
			overlayContext.font = "12px sans-serif";
			overlayContext.textBaseline = "bottom";
			var width = context.measureText("" + value).width;
			overlayContext.fillText(value, c_x + Math.floor(gridSize / 2) - Math.floor(width / 2), c_y);
		}
	}
}

function limit(value, maximum) {
	if (value <= maximum) {
		return {"value":value, "limited":false};
	}
	return {"value":maximum, "limited":true};
}

var o_x = rightLimit;
var o_y = 0;
function coords(e) {
	var x;
	var y;
	if (e.pageX != undefined && e.pageY != undefined) {
		x = e.pageX;
		y = e.pageY;
	}
	else {
		x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
		y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
	}

	x -= display.offsetLeft;
	y -= display.offsetTop;

	return { "x":x, "y":y };
}

function coordsToPosition(coords) {
	return {
		"row": Math.floor(coords.y / (2 * gutterSize + gridSize)),
		"column": Math.floor((coords.x) / gridSize)
	};
}

var dragging = false;
function mouseDown(e) {
	switch (e.which) {
		case 3:
			alert("RIGHT CLICK");
			break;
		default:
			dragging = e;
			stopPolling();
			polling = false;
			var c = coords(e);
			c.x -= o_x;
			selected = coordsToPosition(c);
			$("#debug").text("Selected: " + selected.row + " " + selected.column);
			fetchData();
	}
}

function mouseUp(e) {
	dragging = false;
	polling = true;
}

function clearEverything() {
	clearCanvas();
	clearOverlay();
	clearUnderlay();
	clearScale();
}

function mouseMove(e) {
	if (dragging) {
		clearEverything()
		var m_coords = coords(e);
		var d_coords = coords(dragging);
		o_x += m_coords.x - d_coords.x;
		if (o_x > 0) {
			o_x = 0;
			//alert("This application can only show 7 days worth of data.\n\nThis restriction could be removed if you raise a change request with the Diffa development team.")
		}

		if (Math.abs(o_x) > rightLimit) {
			o_x = -1 * rightLimit;
		}
		context.translate(o_x, o_y);
		scaleContext.translate(o_x, 0);
		drawGrid();
		dragging = e;
		$("#debug").text("Offset " + o_x + " " + rightLimit);
	}
	else {
		clearOverlay();
		overlayContext.translate(o_x, o_y);
		mouseOver(e);
	}
}

function mouseOver(e) {
	var c = coords(e);
	c.x -= o_x;
	var position = coordsToPosition(c);
	if (position.row >= 0 && position.row < maxRows && position.column >= 0 && position.column < maxColumns) {
		highlighted = position;
		drawOverlay();
	}
}

function initGraph() {
	createSession();
	initCanvas();
	startPolling();

	$(document).mouseup(mouseUp);
	$("#display").mousedown(mouseDown);
	$(document).mousemove(mouseMove);

	$("#display").bind("contextmenu", function(e) {
		return false;
	});

	$("#polling").toggle(
		function() {
			if(polling)	{
				stopPolling();
			}
		},
		function() {
			startPolling();
		}
	);
}
<|endoftext|>


<commit_before>var db = require('../../db');

module.exports = function(server) {
    // Sample usage:
    // % curl -X POST 'http://localhost:5000/user/purchase' -d 'user=3&game=9'
    server.post({
        url: '/user/purchase',
        swagger: {
            nickname: 'purchase',
            notes: 'Record that a user has purchased this game',
            summary: 'Purchase game'
        },
        validation: {
            user: {
                description: 'User (ID or username slug)',
                isRequired: true
            },
            game: {
                description: 'Game (ID or slug)',
                isRequired: true
            }
        }
    }, function(req, res) {
        var POST = req.params;

        // TODO: Accept ID *or* slug.
        var user = POST.user;
        var game = POST.game;

        // TODO: Require SSA.
        if (!user) {
            res.json(403, {error: 'bad_user'});
        }
        if (!game) {
            res.json(403, {error: 'bad_game'});
        }

        var redisClient = db.redis();
        redisClient.sadd('gamesPurchased:' + user, game, function() {
            redisClient.end();
        });

        return res.json({success: true});
    });
};
<commit_msg>Polish purchase view Also English.<commit_after>var auth = require('../../lib/auth');
var db = require('../../db');

module.exports = function(server) {
    // Sample usage:
    // % curl -X POST 'http://localhost:5000/user/purchase' -d 'user=ssatoken&game=9'
    server.post({
        url: '/user/purchase',
        swagger: {
            nickname: 'purchase',
            notes: 'Record that a user has purchased this game',
            summary: 'Purchase game'
        },
        validation: {
            user: {
                description: 'User (ID or username slug)',
                isRequired: true
            },
            game: {
                description: 'Game (ID or slug)',
                isRequired: true
            }
        }
    }, function(req, res) {
        var POST = req.params;

        // TODO: Accept ID *or* slug.
        var user = POST.user;
        var email;
        if (!user || !(email = auth.confirmSSA(user))) {
            res.json(403, {error: 'bad_user'});
        }
        // TODO: Change email to user ID.

        var game = POST.game;
        if (!game) {
            res.json(403, {error: 'bad_game'});
        }

        var redisClient = db.redis();
        redisClient.sadd('gamesPurchased:' + email, game, function(err) {
            if (err) {
                res.json(500, {error: 'internal_db_error'});
                return;
            }
            redisClient.end();
            res.json({success: true});
        });
    });
};
<|endoftext|>


<commit_before>/*jshint esversion: 6 */

/*
  Manage Menu View to select and unselect proposition of element/link
*/
class AskomicsMenu {

  constructor (nameMenu,buttonMenu,listObjectMenu,functFillMenu,removeWhenReset=true) {
    this.name = nameMenu;
    this.buttonMenu = buttonMenu;
    this.listObjectMenu = listObjectMenu ;
    this.func = functFillMenu ;
    this.removeWhenReset = removeWhenReset ;
  }

  reset() {
    let menu = this ;
    // Remove onclick
    $("#"+menu.buttonMenu).unbind();
    if (menu.removeWhenReset)
      $("#"+menu.listObjectMenu).empty();
  }

  start() {
    let menu = this ;
    $("#"+menu.buttonMenu).prop('disabled', false);
    $("#"+menu.buttonMenu)
    .on('mousedown', function(event) {
      if ( $("#"+menu.listObjectMenu).is(':visible') ) {
        $("#"+menu.listObjectMenu).slideUp();
      }
      else {
        menu.slideUp();
        $("#"+menu.listObjectMenu).slideDown();
      }
      event.stopPropagation();
    });
    menu.func(menu);
    //hide by default
    $("#"+menu.listObjectMenu).hide();
  }

  slideUp() {
    $("#menuGraph").find("ul").slideUp();
  }
}

/**************************************************************************/
/**/
/**/
/* Shortcuts Menu */
/**/
/**/
var fileFuncMenu = function(menu) {
  //$("#uploadedQuery")
  $("#dwl-query").on('click', function(d) {
    var date = new Date().getTime();
    $(this).attr("href", "data:application/octet-stream," + encodeURIComponent(__ihm.getGraphBuilder().getInternalState())).attr("download", "query-" + date + ".json");
  });

  $("#dwl-query-sparql").on('click', function(d) {
    var service = new RestServiceJs("getSparqlQueryInTextFormat");
    var jdata = prepareQuery(false,0, false);
    var date = new Date().getTime();
    var current = this;
    var query = "" ;
    service.postsync(jdata,function(data) {
      query = data.query;
    });
    $(this).attr("href", "data:application/sparql-query," + encodeURIComponent(query)).attr("download", "query-" + date + ".rq");
  });
};

/**************************************************************************/
/**/
/**/
/* Shortcuts Menu */
/**/
/**/
var shortcutsFuncMenu = function(menu) {

  var buildLiView = function (uri,label,submenu) {

    var icheck = $("")
        .attr("class","glyphicon glyphicon-check")
        .css("visibility","hidden");

    var a = $("")
            .attr("href","#")
            .attr("class","small")
            .attr("tabIndex","-1") ;
    if (submenu) {
      a.html($("").append(label+"\t")).append(icheck);
    } else {
      a.html($("").append(label+"\t")).append(icheck);
    }
    var li = $("

");
    li.attr("uri",uri);
    li.css("display","table-cell");
    li.css("vertical-align","middle");
    li.append(a);
    return li;
  };

  let lshortcuts = new ShortcutsParametersView().getAllShortcuts();
  /*
  if (lshortcuts.length <= 0) {
    $("#buttonViewListShortcuts").removeClass('active');
    $("#buttonViewListShortcuts").addClass('disabled');

  } else {
    $("#buttonViewListShortcuts").removeClass('disabled');
    $("#buttonViewListShortcuts").addClass('active');
  }
*/
  //console.log(JSON.stringify(lshortcuts));
  $.each(lshortcuts, function(i) {
    var li = buildLiView(i,lshortcuts[i].label,false);
    __ihm.getSVGLayout().offProposedUri("shortcuts",i);

    li.on('click', function() {
      var span = $(this).find(".glyphicon");
      var cur_uri = $(this).attr("uri");
      if ( span.css("visibility") == "visible" ) {
        span.css("visibility","hidden");
        __ihm.getSVGLayout().offProposedUri("shortcuts",cur_uri);
      } else {
        span.css("visibility","visible");
        __ihm.getSVGLayout().onProposedUri("shortcuts",cur_uri);
      }
      // remove old suggestion
      __ihm.getSVGLayout().removeSuggestions();
      // insert new suggestion
      __ihm.getSVGLayout().insertSuggestions();
      // regenerate the graph
      __ihm.getSVGLayout().update();
    });
    $("#"+menu.listObjectMenu).append(li);
    $("#"+menu.listObjectMenu).append($("

").attr("class","divider"));
    /* next entity */
  });

  /* remove button if no shortcuts */
  if ( Object.keys(lshortcuts).length <= 0 ) {
    $("#"+menu.buttonMenu).prop('disabled', true);
  }

};
/**************************************************************************/
/**/
/**/
/* Shortcuts Menu */
/**/
/**/
var entitiesAndRelationsFuncMenu = function(menu) {
  var buildLiView = function(uri,label,submenu,hidden) {

    var icheck = $("")
        .attr("class","glyphicon glyphicon-check");

    if (hidden) {
      icheck.css("visibility","hidden");
    }
    var a = $("")
            .attr("href","#")
            .attr("class","small")
            .attr("tabIndex","-1") ;
    if (submenu) {
      a.html($("").append(label+"\t")).append(icheck);
    } else {
      a.html($("").append(label+"\t")).append(icheck);
    }
    var li = $("

");
    li.attr("uri",uri);
    li.css("display","table-cell");
    li.css("vertical-align","middle");
    li.append(a);
    return li;
  };
  var menuView = menu;
  //
<input type="checkbox"/> Option 1

  let lentities = Object.keys(__ihm.getAbstraction().getEntities());

  $.each(lentities, function(i) {

    let node = new GraphObject({'uri' : lentities[i]});
    let nodeuri = node.uri;
    var li = buildLiView(nodeuri,node.removePrefix(),false,false);

    li.on('click', function() {
      var span = $(this).find(".glyphicon");
      var cur_uri = $(this).attr("uri");
      if ( span.css("visibility") == "visible" ) {
        span.css("visibility","hidden");
        __ihm.getSVGLayout().offProposedUri("node",cur_uri);
        // disable all predicate associated with this node
        $(this).parent().parent().find("li[nodeuri='"+cur_uri+"']").attr("class","disabled");
      } else {
        span.css("visibility","visible");
        __ihm.getSVGLayout().onProposedUri("node",cur_uri);
        // enable all predicate associated with this node
        $(this).parent().parent().find("li[nodeuri='"+cur_uri+"']").removeAttr("class");
      }
      // remove old suggestion
      __ihm.getSVGLayout().removeSuggestions();
      // insert new suggestion
      __ihm.getSVGLayout().insertSuggestions();
      // regenerate the graph
      __ihm.getSVGLayout().update();
    });

    $("#"+menuView.listObjectMenu).append(li);
    /* --------------------------- */
    /* Adding filter on relations  */
    /* --------------------------- */

    let tab = __ihm.getAbstraction().getRelationsObjectsAndSubjectsWithURI(nodeuri);
    let listRelObj = tab[0];

    $.each(listRelObj, function(objecturi) {
      let object = new GraphObject({uri:objecturi});
      $.each(listRelObj[objecturi], function(idxrel) {
        let rel = listRelObj[objecturi][idxrel];
        let linkRel = new GraphObject({uri:rel});
        let li = buildLiView(rel,linkRel.removePrefix()+"→"+object.removePrefix(),true,false);

        li.attr("nodeuri",nodeuri)
          .on('click', function() {
            /* when this li is unavailable, we can do nothing */
            if ( $(this).attr("class") === "disabled" ) return ;

            var span = $(this).find(".glyphicon");
            var cur_uri = $(this).attr("uri");
            if ( span.css("visibility") == "visible" ) {
             span.css("visibility","hidden");
             __ihm.getSVGLayout().offProposedUri("link",cur_uri);
            } else {
             span.css("visibility","visible");
             __ihm.getSVGLayout().onProposedUri("link",cur_uri);
           }
           /* remove old suggestion */
           __ihm.getSVGLayout().removeSuggestions();
           /* insert new suggestion */
           __ihm.getSVGLayout().insertSuggestions();
           /* regenerate the graph */
           __ihm.getSVGLayout().update();
        });
        $("#"+menuView.listObjectMenu).append(li);
      });
    });
    $("#"+menuView.listObjectMenu).append($("

").attr("class","divider"));
    /* next entity */
  });

  let positionableEntities = __ihm.getAbstraction().getPositionableEntities();
  if (Object.keys(positionableEntities).length>0) {
    /* positionable object */
    let posuri = "positionable";
    let li = buildLiView(posuri,posuri,false,true);
    __ihm.getSVGLayout().offProposedUri("link",posuri);

    li.attr("nodeuri",posuri)
      .on('click', function() {
        var span = $(this).find(".glyphicon");
        var cur_uri = $(this).attr("uri");
        if ( span.css("visibility") == "visible" ) {
          span.css("visibility","hidden");
          __ihm.getSVGLayout().offProposedUri("link",cur_uri);
        } else {
          span.css("visibility","visible");
          __ihm.getSVGLayout().onProposedUri("link",cur_uri);
        }
        /* remove old suggestion */
        __ihm.getSVGLayout().removeSuggestions();
        /* insert new suggestion */
        __ihm.getSVGLayout().insertSuggestions();
        /* regenerate the graph */
        __ihm.getSVGLayout().update();
      });
      $("#"+menuView.listObjectMenu).append(li);
      //$("#viewListNodesAndLinks").append($("

").attr("class","divider"));
    }
};

/**************************************************************************/
/**/
/**/
/* Shortcuts Menu */
/**/
/**/
var graphFuncMenu = function(menu) {
  var buildLiView = function (uri,label,submenu) {

    var icheck = $("")
        .attr("class","glyphicon glyphicon-check");

    var a = $("")
            .attr("href","#")
            .attr("class","small")
            .attr("tabIndex","-1") ;
    if (submenu) {
      a.html($("").append(label+"\t")).append(icheck);
    } else {
      a.html($("").append(label+"\t")).append(icheck);
    }
    var li = $("

");
    li.attr("uri",uri);
    li.css("display","table-cell");
    li.css("vertical-align","middle");
    li.append(a);
    return li;
  };

  let listGraph = __ihm.getAbstraction().listGraphAvailable();

  $.each(listGraph, function(g) {
    let graph = g;
    let li = buildLiView(graph,graph,true);
    li.on('click',function() {
        var span = $(this).find(".glyphicon");
        var cur_uri = $(this).attr("uri");
        if ( span.css("visibility") == "visible" ) {
          span.css("visibility","hidden");
          __ihm.getAbstraction().unactiveGraph(cur_uri);
        } else {
          span.css("visibility","visible");
          __ihm.getAbstraction().activeGraph(cur_uri);
        }
        /* remove old suggestion */
        __ihm.getSVGLayout().removeSuggestions();
        /* insert new suggestion */
        __ihm.getSVGLayout().insertSuggestions();
        /* regenerate the graph */
        __ihm.getSVGLayout().update();
      });
    $("#"+menu.listObjectMenu).append(li).append($("

"));
  });
};
<commit_msg>- update menu view when graph are unselected/selected<commit_after>/*jshint esversion: 6 */

/*
  Manage Menu View to select and unselect proposition of element/link
*/
class AskomicsMenu {

  constructor (nameMenu,buttonMenu,listObjectMenu,functFillMenu,removeWhenReset=true) {
    this.name = nameMenu;
    this.buttonMenu = buttonMenu;
    this.listObjectMenu = listObjectMenu ;
    this.func = functFillMenu ;
    this.removeWhenReset = removeWhenReset ;
  }

  reset() {
    let menu = this ;
    // Remove onclick
    $("#"+menu.buttonMenu).unbind();
    if (menu.removeWhenReset)
      $("#"+menu.listObjectMenu).empty();
  }

  start() {
    let menu = this ;
    $("#"+menu.buttonMenu).prop('disabled', false);
    $("#"+menu.buttonMenu)
    .on('mousedown', function(event) {
      if ( $("#"+menu.listObjectMenu).is(':visible') ) {
        $("#"+menu.listObjectMenu).slideUp();
      }
      else {
        menu.slideUp();
        $("#"+menu.listObjectMenu).slideDown();
      }
      event.stopPropagation();
    });
    menu.func(menu);
    //hide by default
    $("#"+menu.listObjectMenu).hide();
  }

  slideUp() {
    $("#menuGraph").find("ul").slideUp();
  }
}

/**************************************************************************/
/**/
/**/
/* Shortcuts Menu */
/**/
/**/
var fileFuncMenu = function(menu) {
  //$("#uploadedQuery")
  $("#dwl-query").on('click', function(d) {
    var date = new Date().getTime();
    $(this).attr("href", "data:application/octet-stream," + encodeURIComponent(__ihm.getGraphBuilder().getInternalState())).attr("download", "query-" + date + ".json");
  });

  $("#dwl-query-sparql").on('click', function(d) {
    var service = new RestServiceJs("getSparqlQueryInTextFormat");
    var jdata = prepareQuery(false,0, false);
    var date = new Date().getTime();
    var current = this;
    var query = "" ;
    service.postsync(jdata,function(data) {
      query = data.query;
    });
    $(this).attr("href", "data:application/sparql-query," + encodeURIComponent(query)).attr("download", "query-" + date + ".rq");
  });
};

/**************************************************************************/
/**/
/**/
/* Shortcuts Menu */
/**/
/**/
var shortcutsFuncMenu = function(menu) {

  var buildLiView = function (uri,label,submenu) {

    var icheck = $("")
        .attr("class","glyphicon glyphicon-check")
        .css("visibility","hidden");

    var a = $("")
            .attr("href","#")
            .attr("class","small")
            .attr("tabIndex","-1") ;
    if (submenu) {
      a.html($("").append(label+"\t")).append(icheck);
    } else {
      a.html($("").append(label+"\t")).append(icheck);
    }
    var li = $("

");
    li.attr("uri",uri);
    li.css("display","table-cell");
    li.css("vertical-align","middle");
    li.append(a);
    return li;
  };

  let lshortcuts = new ShortcutsParametersView().getAllShortcuts();
  /*
  if (lshortcuts.length <= 0) {
    $("#buttonViewListShortcuts").removeClass('active');
    $("#buttonViewListShortcuts").addClass('disabled');

  } else {
    $("#buttonViewListShortcuts").removeClass('disabled');
    $("#buttonViewListShortcuts").addClass('active');
  }
*/
  //console.log(JSON.stringify(lshortcuts));
  $.each(lshortcuts, function(i) {
    var li = buildLiView(i,lshortcuts[i].label,false);
    __ihm.getSVGLayout().offProposedUri("shortcuts",i);

    li.on('click', function() {
      var span = $(this).find(".glyphicon");
      var cur_uri = $(this).attr("uri");
      if ( span.css("visibility") == "visible" ) {
        span.css("visibility","hidden");
        __ihm.getSVGLayout().offProposedUri("shortcuts",cur_uri);
      } else {
        span.css("visibility","visible");
        __ihm.getSVGLayout().onProposedUri("shortcuts",cur_uri);
      }
      // remove old suggestion
      __ihm.getSVGLayout().removeSuggestions();
      // insert new suggestion
      __ihm.getSVGLayout().insertSuggestions();
      // regenerate the graph
      __ihm.getSVGLayout().update();
    });
    $("#"+menu.listObjectMenu).append(li);
    $("#"+menu.listObjectMenu).append($("

").attr("class","divider"));
    /* next entity */
  });

  /* remove button if no shortcuts */
  if ( Object.keys(lshortcuts).length <= 0 ) {
    $("#"+menu.buttonMenu).prop('disabled', true);
  }

};
/**************************************************************************/
/**/
/**/
/* Shortcuts Menu */
/**/
/**/
var entitiesAndRelationsFuncMenu = function(menu) {
  var buildLiView = function(uri,label,submenu,hidden) {

    var icheck = $("")
        .attr("class","glyphicon glyphicon-check");

    if (hidden) {
      icheck.css("visibility","hidden");
    }
    var a = $("")
            .attr("href","#")
            .attr("class","small")
            .attr("tabIndex","-1") ;
    if (submenu) {
      a.html($("").append(label+"\t")).append(icheck);
    } else {
      a.html($("").append(label+"\t")).append(icheck);
    }
    var li = $("

");
    li.attr("uri",uri);
    li.css("display","table-cell");
    li.css("vertical-align","middle");
    li.append(a);
    return li;
  };
  var menuView = menu;
  //
<input type="checkbox"/> Option 1

  let lentities = Object.keys(__ihm.getAbstraction().getEntities());

  $.each(lentities, function(i) {

    let node = new GraphObject({'uri' : lentities[i]});
    let nodeuri = node.uri;
    var li = buildLiView(nodeuri,node.removePrefix(),false,false);

    li.on('click', function() {
      var span = $(this).find(".glyphicon");
      var cur_uri = $(this).attr("uri");
      if ( span.css("visibility") == "visible" ) {
        span.css("visibility","hidden");
        __ihm.getSVGLayout().offProposedUri("node",cur_uri);
        // disable all predicate associated with this node
        $(this).parent().parent().find("li[nodeuri='"+cur_uri+"']").attr("class","disabled");
      } else {
        span.css("visibility","visible");
        __ihm.getSVGLayout().onProposedUri("node",cur_uri);
        // enable all predicate associated with this node
        $(this).parent().parent().find("li[nodeuri='"+cur_uri+"']").removeAttr("class");
      }
      // remove old suggestion
      __ihm.getSVGLayout().removeSuggestions();
      // insert new suggestion
      __ihm.getSVGLayout().insertSuggestions();
      // regenerate the graph
      __ihm.getSVGLayout().update();
    });

    $("#"+menuView.listObjectMenu).append(li);
    /* --------------------------- */
    /* Adding filter on relations  */
    /* --------------------------- */

    let tab = __ihm.getAbstraction().getRelationsObjectsAndSubjectsWithURI(nodeuri);
    let listRelObj = tab[0];

    $.each(listRelObj, function(objecturi) {
      let object = new GraphObject({uri:objecturi});
      $.each(listRelObj[objecturi], function(idxrel) {
        let rel = listRelObj[objecturi][idxrel];
        let linkRel = new GraphObject({uri:rel});
        let li = buildLiView(rel,linkRel.removePrefix()+"→"+object.removePrefix(),true,false);

        li.attr("nodeuri",nodeuri)
          .on('click', function() {
            /* when this li is unavailable, we can do nothing */
            if ( $(this).attr("class") === "disabled" ) return ;

            var span = $(this).find(".glyphicon");
            var cur_uri = $(this).attr("uri");
            if ( span.css("visibility") == "visible" ) {
             span.css("visibility","hidden");
             __ihm.getSVGLayout().offProposedUri("link",cur_uri);
            } else {
             span.css("visibility","visible");
             __ihm.getSVGLayout().onProposedUri("link",cur_uri);
           }
           /* remove old suggestion */
           __ihm.getSVGLayout().removeSuggestions();
           /* insert new suggestion */
           __ihm.getSVGLayout().insertSuggestions();
           /* regenerate the graph */
           __ihm.getSVGLayout().update();
        });
        $("#"+menuView.listObjectMenu).append(li);
      });
    });
    $("#"+menuView.listObjectMenu).append($("

").attr("class","divider"));
    /* next entity */
  });

  let positionableEntities = __ihm.getAbstraction().getPositionableEntities();
  if (Object.keys(positionableEntities).length>0) {
    /* positionable object */
    let posuri = "positionable";
    let li = buildLiView(posuri,posuri,false,true);
    __ihm.getSVGLayout().offProposedUri("link",posuri);

    li.attr("nodeuri",posuri)
      .on('click', function() {
        var span = $(this).find(".glyphicon");
        var cur_uri = $(this).attr("uri");
        if ( span.css("visibility") == "visible" ) {
          span.css("visibility","hidden");
          __ihm.getSVGLayout().offProposedUri("link",cur_uri);
        } else {
          span.css("visibility","visible");
          __ihm.getSVGLayout().onProposedUri("link",cur_uri);
        }
        /* remove old suggestion */
        __ihm.getSVGLayout().removeSuggestions();
        /* insert new suggestion */
        __ihm.getSVGLayout().insertSuggestions();
        /* regenerate the graph */
        __ihm.getSVGLayout().update();
      });
      $("#"+menuView.listObjectMenu).append(li);
      //$("#viewListNodesAndLinks").append($("

").attr("class","divider"));
    }
};

/**************************************************************************/
/**/
/**/
/* Shortcuts Menu */
/**/
/**/
var graphFuncMenu = function(menu) {
  var buildLiView = function (uri,label,submenu) {

    var icheck = $("")
        .attr("class","glyphicon glyphicon-check");

    var a = $("")
            .attr("href","#")
            .attr("class","small")
            .attr("tabIndex","-1") ;
    if (submenu) {
      a.html($("").append(label+"\t")).append(icheck);
    } else {
      a.html($("").append(label+"\t")).append(icheck);
    }
    var li = $("

");
    li.attr("uri",uri);
    li.css("display","table-cell");
    li.css("vertical-align","middle");
    li.append(a);
    return li;
  };

  let listGraph = __ihm.getAbstraction().listGraphAvailable();

  $.each(listGraph, function(g) {
    let graph = g;
    let li = buildLiView(graph,graph,true);
    li.on('click',function() {
        var span = $(this).find(".glyphicon");
        var cur_uri = $(this).attr("uri");
        if ( span.css("visibility") == "visible" ) {
          span.css("visibility","hidden");
          __ihm.getAbstraction().unactiveGraph(cur_uri);
        } else {
          span.css("visibility","visible");
          __ihm.getAbstraction().activeGraph(cur_uri);
        }
        /* update menu view with relations and objects availables */
        __ihm.menus.menuView.reset();
        __ihm.menus.menuView.start();

        /* remove old suggestion */
        __ihm.getSVGLayout().removeSuggestions();
        /* insert new suggestion */
        __ihm.getSVGLayout().insertSuggestions();
        /* regenerate the graph */
        __ihm.getSVGLayout().update();
      });
    $("#"+menu.listObjectMenu).append(li).append($("

"));
  });
};
<|endoftext|>


<commit_before>const image1 = '/static/images/avatar-01.svg';
const image2 = '/static/images/avatar-02.svg';
const image3 = '/static/images/avatar-03.svg';
const image4 = '/static/images/avatar-04.svg';

const avatars = [image1, image2, image3, image4];

const logos = [
  '/public/images/code.svg',
  '/public/images/rocket.svg',
  '/public/images/repo.svg',
];

export function pickAvatar(NameOrId) {
  return pickRandomImage(avatars, NameOrId);
}

export function pickLogo(NameOrId) {
  return pickRandomImage(logos, NameOrId);
}

export function pickRandomImage(images, NameOrId) {
  let number = 0;
  if (isNaN(NameOrId)) {
    for (let i = 0; i < NameOrId.length; i++) {
      number += NameOrId.charCodeAt(i);
    }
  } else {
    number = NameOrId;
  }
  return images[number % 4];
}<commit_msg>fix for new user profile page<commit_after>const image1 = '/static/images/avatar-01.svg';
const image2 = '/static/images/avatar-02.svg';
const image3 = '/static/images/avatar-03.svg';
const image4 = '/static/images/avatar-04.svg';

const avatars = [image1, image2, image3, image4];

const logos = [
  '/public/images/code.svg',
  '/public/images/rocket.svg',
  '/public/images/repo.svg',
];

export function pickAvatar(NameOrId) {
  return pickRandomImage(avatars, NameOrId);
}

export function pickLogo(NameOrId) {
  return pickRandomImage(logos, NameOrId);
}

export function pickRandomImage(images, NameOrId = 0) {
  let number = 0;
  if (isNaN(NameOrId)) {
    for (let i = 0; i < NameOrId.length; i++) {
      number += NameOrId.charCodeAt(i);
    }
  } else {
    number = NameOrId;
  }
  return images[number % 4];
}<|endoftext|>


<commit_before>var fs = require('fs'),
    path = require('path'),
    util = require('util'),
    http = require('http'),
    io = require('socket.io-client'),
    sutil = require('./lib/client-utils'),
    serialport = require('serialport'),
    SerialPort = serialport.SerialPort;

// base config for beagle
var config =  {
    dojoHost: 'http://ninjdojo.herokuapp.com',
    dojoPort:80,
    cloudHost: 'ninj.herokuapp.com',
    cloudPort: 80,
    devtty: "/dev/ttyO1",
    serialFile: "/utilities/etc/serial.conf",
    tokenFile: "/utilities/etc/token.conf",
    heartbeat_interval: 500
};
var nodedetails = {};
// commandline config overwrites
if (process.argv[2] == 'local') {
    config.dojoHost = '10.10.0.35';
    config.dojoPort = '3001';
    config.cloudHost = '10.10.0.35';
    config.cloudPort = 3000;
}
if (process.argv[3] == 'ftdi') {
    config.devtty = "/dev/tty.usbserial-AE01AAE3";
    config.serialFile = __dirname+"/serialnumber";
    config.tokenFile = __dirname+"/token";
}
console.log(config);
var tty = new SerialPort(config.devtty, {
    parser: serialport.parsers.readline("\n")
});
/*
*   Serial Port Stuff
*/
var activationRequiredState = function() {
    console.log("Entered activated requried state");
    changeLEDColor('purple');
    var cmdOptions = {
        host: config.cloudHost,
        port: config.cloudPort,
        path: '/a/block_activation/'+nodedetails.id,
        method: 'GET'
    };
    var longPollConn={};
    var killLongPoll = false;
    var longpoll = function(){
        if (longPollConn.end) longPollConn.end();
        longPollConn = http.get(cmdOptions, function (http_res) {
            http_res.on("data", function (data) {
                parseResponse(data);
            });
            http_res.on("end", function () {
                if (!killLongPoll) longpoll();
            });
            http_res.on("close", function () {
                if (!killLongPoll) longpoll();
            });
            http_res.on("error", function () {
                setTimeout(longpoll,5000);
            });

        }).on('error',function(err){
            console.log('Error in longpoll request: '+err);
            setTimeout(longpoll,5000)
        });
    };

    var parseResponse = function(data){
        // write it to the fs
        var data = sutil.getJSON(data) || false;
        if (data && data.token) {
            fs.writeFileSync(config.tokenFile, data.token, 'utf8');
            nodedetails["token"] = data.token;
            killLongPoll = true;
            longPollConn.end();
            activatedState();   // Set state to activated
        }
    }
    longpoll();
};

var changeLEDColor = function(color) {
    switch (color) {
        case 'purple':
            var hex = 'FF00FF';
        break;
        case 'green':
            var hex = '00FF00';
        break;
        case 'red':
            var hex = 'FF0000';
        break;
        case 'cyan':
            var hex = '00FFFF';
        break;
        default:
            var hex = '000000';
        break;
    }
    sutil.writeTTY(tty,'{"DEVICE":[{"G":"0","V":0,"D":1000,"DA":"'+hex+'"}]}');
}

var activatedState = function() {
    console.log("Entered activated state");

    var readings = {};
    tty.on('data',function(data){
         //console.log(data); // the almost raw serial data
        var nm = sutil.getJSON(data) || false;
        if (nm) {
            // only keep latest reading per device between heartbeats
            for (var x=0; x<nm.DEVICE.length; x++) {
                nm.DEVICE[x].GUID = nodedetails.id+'_'+nm.DEVICE[x].G+'_'+nm.DEVICE[x].V+'_'+nm.DEVICE[x].D;
                readings[nm.DEVICE[x].GUID] = nm.DEVICE[x];
            }
        }
    });

    var getHeartbeat = function(){
        var hb = {
            "NODE_ID":nodedetails.id,
            "TOKEN": nodedetails.token,
            "TIMESTAMP": null,
            "DEVICE":[]
        };
        hb.TIMESTAMP = new Date().getTime();
        for (r in readings) {
            hb.DEVICE.unshift(readings[r]);
            delete readings[r];
        }
        return JSON.stringify(hb);
    }
    var ioOpts = {
        'port':config.dojoPort,
        'transports':['xhr-polling'],
        'try multiple transports':false
    };
    var socket = io.connect(config.dojoHost,ioOpts);

    var sendIv;
    socket.on('connecting',function(transport){
        currentState="connecting";
        changeLEDColor('cyan');
    });
    socket.on('connect', function () {
        console.log("Connected");
        sendingData=true;
        setStateToOK();
        clearInterval(sendIv);
        sendIv = setInterval(function(){
            if (beatThrottle.isGoodToGo()) {
                socket.send(getHeartbeat());
            }
        },config.heartbeat_interval);
    });

    socket.on('error',function() {
        setTimeout(function () {
            socket = io.connect(config.dojoHost);
        }, 1000);
        sendingData=false;
        setStateToError();
    });

    socket.on('disconnect', function () {
        // socket disconnected
        setTimeout(function () {
            socket = io.connect(config.dojoHost);
        }, 1000);
        sendingData=false;
        setStateToError();
    });
    /*
    socket.on('connect_failed', function () {

        // socket cannot reconnect. Keep trying
        setTimeout(function () {
            socket = io.connect(config.dojoHost);
        }, 1000);
    });
    */
    var emptyBeats = 0;

    var beatThrottle = {
        isGoodToGo : function() {
            if (!sutil.isEmpty(readings) || beatThrottle.counter>beatThrottle.rate) {
                beatThrottle.counter = 0;
                return true;
            } else {
                beatThrottle.counter++;
                return false;
            }
        },
        rate : 10000/config.heartbeat_interval,
        counter: 0
    };
    /*
    *   Receiving Data
    */
    var cmdOptions = {
        host: config.cloudHost,
        port: config.cloudPort,
        path: '/commands/'+nodedetails.id,
        method: 'GET'
    }
    var longPollConn={};
    var longpoll = function(){
        if (longPollConn.end) longPollConn.end();
        longPollConn = http.get(cmdOptions, function (http_res) {
            http_res.on("data", function (data) {
                receivingData=true;
                setStateToOK();
                executeCommand(data);
            });
            http_res.on("end", function () {
                longpoll();
            });
            http_res.on("close", function () {
                longpoll();
            });
            http_res.on("error", function () {
                setTimeout(longpoll,5000)
            });

        }).on('error',function(err){
            console.log('Error in longpoll request: '+err);
            setTimeout(longpoll,5000);
            receivingData=false;
            setStateToError();
        });
    }

    var executeCommand = function(data){
        if (data.welcome) return;
        var ds = sutil.getJSON(data).DEVICE;
        if (ds && ds.length>0) {
            for (d in ds) {
                delete ds[d].GUID;
                ds[d].G = ds[d].G.toString(); //TODO get JP to fix for 0
                sutil.writeTTY(tty,'{"DEVICE":['+JSON.stringify(ds[d])+']}');
            }
        } else {
            console.log(data.toString());
        }
    }
    longpoll();
};
// main() -- basically
var sendingData = false;
var receivingData = false;
var currentState;
var setStateToOK = function() {
    if (sendingData && receivingData && currentState!=='ok') {
        changeLEDColor('green');
        currentState="ok";
    }
};

var setStateToError = function() {
    currentState='error';
    changeLEDColor('red');
};

(function() {
    nodedetails["id"] = fs.readFileSync(config.serialFile).toString().replace(/\n/g,''); // TODO

    if (path.existsSync(config.tokenFile)) {
        // We're good to go
        nodedetails["token"] = fs.readFileSync(config.tokenFile).toString().replace(/\n/g,''); // TODO
        activatedState();
    }
    else {
        // Need to request a token
        activationRequiredState();
    }
})();<commit_msg>Various<commit_after>var fs = require('fs'),
    path = require('path'),
    util = require('util'),
    http = require('http'),
    io = require('socket.io-client'),
    sutil = require('./lib/client-utils'),
    serialport = require('serialport'),
    SerialPort = serialport.SerialPort;

// base config for beagle
var config =  {
    dojoHost: 'http://ninjdojo.herokuapp.com',
    dojoPort:80,
    cloudHost: 'ninj.herokuapp.com',
    cloudPort: 80,
    devtty: "/dev/ttyO1",
    serialFile: "/utilities/etc/serial.conf",
    tokenFile: "/utilities/etc/token.conf",
    heartbeat_interval: 500
};
var nodedetails = {};
// commandline config overwrites
if (process.argv[2] == 'local') {
    config.dojoHost = process.argv[3];
    config.dojoPort = 3001;
    config.cloudHost = process.argv[3];
    config.cloudPort = 3000;
}
if (process.argv[4] == 'ftdi') {
    config.devtty = "/dev/tty.usbserial-AE01AAE3";
    config.serialFile = __dirname+"/serialnumber";
    config.tokenFile = __dirname+"/token";
}
console.log(config);
var tty = new SerialPort(config.devtty, {
    parser: serialport.parsers.readline("\n")
});

var serialport = require('serialport'),
    SerialPort = serialport.SerialPort;
var tty = new SerialPort('/dev/ttyO1', {
    parser: serialport.parsers.readline("\n")
});
tty.on('data',function(data) {
    console.log(data);
});

/*
*   Serial Port Stuff
*/
var activationRequiredState = function() {
    console.log("Entered activated requried state");
    changeLEDColor('purple');
    var cmdOptions = {
        host: config.cloudHost,
        port: config.cloudPort,
        path: '/a/block_activation/'+nodedetails.id,
        method: 'GET'
    };
    var longPollConn={};
    var killLongPoll = false;
    var longpoll = function(){
        if (longPollConn.end) longPollConn.end();
        longPollConn = http.get(cmdOptions, function (http_res) {
            http_res.on("data", function (data) {
                parseResponse(data);
            });
            http_res.on("end", function () {
                if (!killLongPoll) longpoll();
            });
            http_res.on("close", function () {
                if (!killLongPoll) longpoll();
            });
            http_res.on("error", function () {
                setTimeout(longpoll,5000);
            });

        }).on('error',function(err){
            console.log('Error in longpoll request: '+err);
            setTimeout(longpoll,5000)
        });
    };

    var parseResponse = function(data){
        // write it to the fs
        var data = sutil.getJSON(data) || false;
        if (data && data.token) {
            fs.writeFileSync(config.tokenFile, data.token, 'utf8');
            nodedetails["token"] = data.token;
            killLongPoll = true;
            longPollConn.end();
            activatedState();   // Set state to activated
        }
    }
    longpoll();
};

var changeLEDColor = function(color) {
    switch (color) {
        case 'purple':
            var hex = 'FF00FF';
        break;
        case 'green':
            var hex = '00FF00';
        break;
        case 'red':
            var hex = 'FF0000';
        break;
        case 'cyan':
            var hex = '00FFFF';
        break;
        default:
            var hex = '000000';
        break;
    }
    sutil.writeTTY(tty,'{"DEVICE":[{"G":"0","V":0,"D":1000,"DA":"'+hex+'"}]}');
}

var activatedState = function() {
    console.log("Entered activated state");

    var readings = {};
    tty.on('data',function(data){
        //console.log(data); // the almost raw serial data
        var nm = sutil.getJSON(data) || false;
        if (nm) {
            try {
                // only keep latest reading per device between heartbeats
                for (var x=0; x<nm.DEVICE.length; x++) {
                    nm.DEVICE[x].GUID = nodedetails.id+'_'+nm.DEVICE[x].G+'_'+nm.DEVICE[x].V+'_'+nm.DEVICE[x].D;
                    readings[nm.DEVICE[x].GUID] = nm.DEVICE[x];
                }
            } catch(err) {
                console.log(err);
                console.log(nm);
            }

        }
    });

    var getHeartbeat = function(){
        var hb = {
            "NODE_ID":nodedetails.id,
            "TOKEN": nodedetails.token,
            "TIMESTAMP": null,
            "DEVICE":[]
        };
        hb.TIMESTAMP = new Date().getTime();
        for (r in readings) {
            hb.DEVICE.unshift(readings[r]);
            delete readings[r];
        }
        return JSON.stringify(hb);
    }
    var ioOpts = {
        'port':config.dojoPort,
        'transports':['xhr-polling'],
        'try multiple transports':false
    };
    var socket = io.connect(config.dojoHost,ioOpts);

    var sendIv;
    socket.on('connecting',function(transport){
        currentState="connecting";
        changeLEDColor('cyan');
    });
    socket.on('connect', function () {
        console.log("Connected");
        sendingData=true;
        setStateToOK();
        clearInterval(sendIv);
        sendIv = setInterval(function(){
            if (beatThrottle.isGoodToGo()) {
                socket.send(getHeartbeat());
            }
        },config.heartbeat_interval);
    });

    socket.on('error',function() {
        setTimeout(function () {
            socket = io.connect(config.dojoHost);
        }, 1000);
        sendingData=false;
        setStateToError();
    });

    socket.on('disconnect', function () {
        // socket disconnected
        setTimeout(function () {
            socket = io.connect(config.dojoHost);
        }, 1000);
        sendingData=false;
        setStateToError();
    });
    /*
    socket.on('connect_failed', function () {

        // socket cannot reconnect. Keep trying
        setTimeout(function () {
            socket = io.connect(config.dojoHost);
        }, 1000);
    });
    */
    var emptyBeats = 0;

    var beatThrottle = {
        isGoodToGo : function() {
            if (!sutil.isEmpty(readings) || beatThrottle.counter>beatThrottle.rate) {
                beatThrottle.counter = 0;
                return true;
            } else {
                beatThrottle.counter++;
                return false;
            }
        },
        rate : 10000/config.heartbeat_interval,
        counter: 0
    };
    /*
    *   Receiving Data
    */
    var cmdOptions = {
        host: config.cloudHost,
        port: config.cloudPort,
        path: '/commands/'+nodedetails.id,
        method: 'GET'
    }
    var longPollConn={};
    var longpoll = function(){
        if (longPollConn.end) longPollConn.end();
        longPollConn = http.get(cmdOptions, function (http_res) {
            http_res.on("data", function (data) {
                receivingData=true;
                setStateToOK();
                executeCommand(data);
            });
            http_res.on("end", function () {
                longpoll();
            });
            http_res.on("close", function () {
                longpoll();
            });
            http_res.on("error", function () {
                setTimeout(longpoll,5000)
            });

        }).on('error',function(err){
            console.log('Error in longpoll request: '+err);
            setTimeout(longpoll,5000);
            receivingData=false;
            setStateToError();
        });
    }

    var executeCommand = function(data){
        if (data.welcome) return;
        var ds = sutil.getJSON(data).DEVICE;
        if (ds && ds.length>0) {
            for (d in ds) {
                delete ds[d].GUID;
                ds[d].G = ds[d].G.toString(); //TODO get JP to fix for 0
                sutil.writeTTY(tty,'{"DEVICE":['+JSON.stringify(ds[d])+']}');
            }
        } else {
            console.log(data.toString());
        }
    }
    longpoll();
};
// main() -- basically
var sendingData = false;
var receivingData = false;
var currentState;
var setStateToOK = function() {
    if (sendingData && receivingData && currentState!=='ok') {
        changeLEDColor('green');
        currentState="ok";
    }
};

var setStateToError = function() {
    currentState='error';
    changeLEDColor('red');
};

(function() {
    nodedetails["id"] = fs.readFileSync(config.serialFile).toString().replace(/\n/g,''); // TODO

    if (path.existsSync(config.tokenFile)) {
        // We're good to go
        nodedetails["token"] = fs.readFileSync(config.tokenFile).toString().replace(/\n/g,''); // TODO
        activatedState();
    }
    else {
        // Need to request a token
        activationRequiredState();
    }
})();<|endoftext|>