<commit_before>/* global crel */

let MODAL;

function qsa(selector) {
    return Array.from(document.querySelectorAll(selector));
}

function insertBefore(newNode, target) {
    target.parentElement.insertBefore(newNode, target);
}

function buildModal() {
    let closeBtn1, closeBtn2;
    const modalNode = crel(
        'div', {id: 'sparqlit-modal',
                'class': 'modal fade',
                tabindex: -1,
                role: 'dialog',
                'aria-labelledby': 'Sparql-it Modal Dialog'},
        crel('div', {'class': 'modal-dialog', role: 'document'},
             crel('div', {'class': 'modal-content'},
                  crel('div', {'class': 'modal-header'},
                       closeBtn1 = crel('button', {type: 'button',
                                                   'class': 'close',
                                                   'data-dismiss': 'modal',
                                                   'arial-label': 'Close'},
                                        crel('span', {'aria-hidden': true}, 'x')),
                       crel('h4', {'class': 'modal-title',
                                   'id': 'sparql-modal-title'},
                            'SPARQL-it !')),
                  crel('div', {'class': 'modal-body'},
                       crel('pre', {id: 'sparqlit-modal-pre'})),
                  crel('div', {'class': 'modal-footer'},
                       crel('a', {'class': 'btn btn-info',
                                  id: 'sparqlit-modal-exec',
                                  href: '#',
                                  target: '_blank'}, 'Execute'),
                       crel('a', {'class': 'btn btn-info',
                                  id: 'sparqlit-modal-edit',
                                  href: 'http://data.bnf.fr/sparql',
                                  target: '_blank'}, 'Edit'),
                       crel('a', {'class': 'btn btn-info',
                                  id: 'sparqlit-modal-dl',
                                  href: '#',
                                  target: '_blank'}, 'Download (JSON)'),
                       closeBtn2 = crel('button', {type: 'button',
                                                   'class': 'btn btn-default',
                                                   'data-dismiss': 'modal'},
                                        'Close')))));
    closeBtn1.onclick = hideModal;
    closeBtn2.onclick = hideModal;
    return modalNode;
}

function modalBackdrop() {
    return crel('div', {'id': 'sparqlit-modal-backdrop',
                        'class': 'modal-backdrop fade'});
}

function sparqlUrl(query, mimetype) {
    return `http://data.bnf.fr/sparql?query=${encodeURIComponent(query)}&format=${encodeURIComponent(mimetype || 'text/html')}`;
}

function executeQueryLink(querydef) {
    const a = crel('a', {'class': 'sparql-link',
                         target: '_blank',
                         title: 'Execute Query',
                         href: '#'},
                   crel('i', {'class': 'glyphicon glyphicon-search'}),
                   'SPARQL-it');
    a.onclick = (evt) => {showModal(querydef); evt.preventDefault();};
    return a;
}

function sparqlLink(querydef) {
    return crel('span', {'class': 'sparql-it'},
                executeQueryLink(querydef));
}

function authorityMainInfos(pageUri) {
    return {
        title: 'Informations principales',
        query: `
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

SELECT ?uri ?predicate ?object WHERE {

  {
    BIND (<${pageUri}> AS ?uri)
    ?uri ?predicate ?object.
  }

  UNION

  {
    <${pageUri}> foaf:focus ?uri.
    ?uri ?predicate ?object.
  }

}`};
}

function authorDocsQuery(role, authorUri) {
    return {
        title: `Contributions de ${authorUri} avec le rôle ${role}`,
        query:`
PREFIX bnfroles: <http://data.bnf.fr/vocabulary/roles/>
PREFIX rdarelationships: <http://rdvocab.info/RDARelationshipsWEMI/>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT DISTINCT ?manif ?work ?title ?date ?type ?gallica WHERE {

  ?expr bnfroles:${role} <${authorUri}#foaf:Person>.
  ?formerexpr owl:sameAs ?expr.
  ?manif rdarelationships:expressionManifested ?formerexpr ;
         dcterms:title ?title
  OPTIONAL {
    ?manif rdarelationships:workManifested ?work.
  }

  OPTIONAL {
    ?manif rdarelationships:electronicReproduction ?gallica.
  }

  OPTIONAL {
    ?manif dcterms:date ?date.
  }

  OPTIONAL {
    ?formerexpr dcterms:type ?type.
  }

}`};
}

function workDocsQuery(workUri) {
    return {
        title: `Documents associés à l'œuvre ${workUri}`,
        query: `
PREFIX rdarelationships: <http://rdvocab.info/RDARelationshipsWEMI/>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT DISTINCT ?manif ?title ?date ?type ?gallica WHERE {

  ?manif rdarelationships:workManifested <${workUri}#frbr:Work> ;
         rdarelationships:expressionManifested ?formerexpr ;
         dcterms:title ?title

  OPTIONAL {
    ?manif rdarelationships:electronicReproduction ?gallica.
  }

  OPTIONAL {
    ?manif dcterms:date ?date.
  }

  OPTIONAL {
    ?formerexpr dcterms:type ?type.
  }
}`};
}

function relatedAuthorsQuery(authorUri) {
    return {
        title: `Auteurs reliés à ${authorUri}`,
        query: `
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX bnfroles: <http://data.bnf.fr/vocabulary/roles/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

SELECT ?role1 ?manif ?title ?role2 ?author2 ?author2name WHERE {
  ?expr dcterms:contributor <${authorUri}#foaf:Person> ;
        ?role1 <${authorUri}#foaf:Person> ;
        ?role2 ?author2.

  ?author2 a foaf:Person;
       foaf:name ?author2name.

  ?formerexpr owl:sameAs ?expr.
  ?manif rdarelationships:expressionManifested ?formerexpr ;
         dcterms:title ?title.

  FILTER(regex(?role1, 'http://data.bnf.fr/vocabulary/roles'))
  FILTER(regex(?role2, 'http://data.bnf.fr/vocabulary/roles'))
  FILTER(?author2 != <${authorUri}#foaf:Person>)
}`};
}

function placesQuery() {
    return {
        title: 'Lieux documentés dans databnf',
        query: `
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>

SELECT ?geo ?label ?lat ?lng ?geonames WHERE {

  ?geoconcept skos:closeMatch ?rameau ;
    skos:prefLabel ?label ;
    foaf:focus ?geo.

  OPTIONAL {
    ?geoconcept skos:exactMatch ?geonames.
    FILTER(regex(?geonames, 'http://sws.geonames.org/'))
  }

  ?geo geo:lat ?lat ;
       geo:long ?lng.

  ?rameau a skos:Concept.
}
`};
}

function studyDocsQuery(authorityUri) {
    return {
        title: `Documents au sujet de ${authorityUri}`,
        query: `
PREFIX rdarelationships: <http://rdvocab.info/RDARelationshipsWEMI/>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT DISTINCT ?manif ?work ?title ?date ?type ?gallica WHERE {

  ?formerexpr owl:sameAs ?expr.

  ?manif dcterms:subject <${authorityUri}> ;
         rdarelationships:expressionManifested ?formerexpr ;
         dcterms:title ?title.

  OPTIONAL {
    ?manif rdarelationships:workManifested ?work.
  }

  OPTIONAL {
    ?manif rdarelationships:electronicReproduction ?gallica.
  }

  OPTIONAL {
    ?manif dcterms:date ?date.
  }

  OPTIONAL {
    ?formerexpr dcterms:type ?type.
  }

}`};
}

function authorWorksQuery(authorUri) {
    return {
        title: `Œuvres de ${authorUri}`,
        query: `
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rdarelationships: <http://rdvocab.info/RDARelationshipsWEMI/>

SELECT ?work ?title (COUNT(?manif) as ?count) WHERE {
 ?work dcterms:creator <${authorUri}#foaf:Person>;
    dcterms:title ?title.

  ?manif rdarelationships:workManifested ?work.
}
GROUP BY ?work ?title
ORDER BY DESC(?count)
`};
}

function storeQuery(query) {
    if (window.localStorage !== undefined) {
        localStorage.setItem('queryVal_main', JSON.stringify({val: query}));
    }
}

function hackMainInfos(pageUri) {
    const h1 = document.querySelector('h1');
    insertBefore(sparqlLink(authorityMainInfos(pageUri)), h1.firstChild);
}

function hackAuthorDocumentSections(authorUri) {
    qsa('.dtmanifs > h3 > a:first-child').forEach(link => {
        const role = link.href.split('/').pop();
        const h3 = link.parentElement;
        h3.insertBefore(sparqlLink(authorDocsQuery(role, authorUri)), link);
    });
}

function hackRelatedAuthors(authorUri) {
    qsa(`.bloc-contenu a[href="http://data.bnf.fr/linked-authors/${authorUri.slice(32, 40)}"]`).forEach(a => {
        insertBefore(sparqlLink(relatedAuthorsQuery(authorUri)), a);
    });
}

function hackAuthorTitle(authorUri) {
    const div = document.querySelector('#allmanifs');
    insertBefore(sparqlLink(authorWorksQuery(authorUri)), div.firstChild);
}

function hackAuthorPage(pageUri) {
    hackMainInfos(pageUri);
    hackAuthorDocumentSections(pageUri);
    hackRelatedAuthors(pageUri);
    hackStudiesSection(pageUri);
    hackAuthorTitle(pageUri);
}

function hackWorkDocumentSections(workUri) {
    qsa('.dtmanifs > h3').forEach(h3 => {
        h3.insertBefore(sparqlLink(workDocsQuery(workUri)), h3.firstChild);
    });
}

function hackStudiesSection(pageUri) {
    qsa('.bloc-contenu a[href$=studies').forEach(link => {
        insertBefore(sparqlLink(studyDocsQuery(pageUri)), link);
    });
}

function hackGeoDocumentSections(geoUri) {
    qsa('.dtmanifs > h3').forEach(h3 => {
        h3.insertBefore(sparqlLink(studyDocsQuery(geoUri)), h3.firstChild);
    });
}

function hackWorkPage(pageUri) {
    hackMainInfos(pageUri);
    hackWorkDocumentSections(pageUri);
    hackStudiesSection(pageUri);
}

function hackGeoPage(pageUri) {
    hackMainInfos(pageUri);
    hackGeoDocumentSections(pageUri);
}

function hackPeriodicalPage(pageUri) {
    hackMainInfos(pageUri);
}

function hackSubjectPage(pageUri) {
    hackMainInfos(pageUri);
}

function hackPerformancePage(pageUri) {
    hackMainInfos(pageUri);
}

function hackHomePage() {
    const mapBlock = document.querySelector('#map-geo');
    insertBefore(sparqlLink(placesQuery()), mapBlock);
}

function guessPageType() {
    const ogtype = document.querySelector('meta[property="og:type"]');
    if (ogtype && ogtype.content) {
        return ogtype.content;
    }
    const path = document.location.pathname;
    if (path === '/') {
        return 'home';
    } else if (path.startsWith('/date')) {
        return 'date';
    } else if (path.startsWith('/3') || path.startsWith('/4')) {
        const divtype = document.querySelector('#fullpage div[itemtype]'),
              itemtype = divtype ? divtype.getAttribute('itemtype') : null;
        if (itemtype === 'http://schema.org/Periodical') {
            return 'periodical';
        } else if (itemtype === 'http://schema.org/TheaterEvent') {
            return 'performance';
        }
    }
    return null;
}

function showModal(querydef) {
    const {query, title} = querydef;
    if (!MODAL) {
        MODAL = buildModal();
        document.body.appendChild(MODAL);
    }
    const backdrop = modalBackdrop();
    document.body.appendChild(backdrop);
    backdrop.classList.add('in');
    MODAL.style.display = 'block';
    MODAL.classList.add('fade', 'in');
    MODAL.querySelector('#sparql-modal-title').textContent = title || 'SPARQL-it !';
    MODAL.querySelector('#sparqlit-modal-pre').textContent = query;
    MODAL.querySelector('#sparqlit-modal-exec').href = sparqlUrl(query);
    MODAL.querySelector('#sparqlit-modal-dl').href = sparqlUrl(query, 'application/sparql-results+json');
    MODAL.querySelector('#sparqlit-modal-edit').onclick = () => storeQuery(query);
}

function hideModal() {
    const backdrop = document.querySelector('#sparqlit-modal-backdrop');
    backdrop.parentNode.removeChild(backdrop);
    MODAL.classList.remove('fade', 'in');
    MODAL.style.display = 'none';
}

let permalink = document.querySelector('link[rel=bookmark]'),
    pageUri = (permalink === null) ? null : permalink.href;

switch(guessPageType()) {
case 'author':
    hackAuthorPage(pageUri);
    break;
case 'book':
    hackWorkPage(pageUri);
    break;
case 'geopoint':
    hackGeoPage(pageUri);
    break;
case 'periodical':
    hackPeriodicalPage(pageUri);
    break;
case 'article':
    hackSubjectPage(pageUri);
    break;
case 'performance':
    hackPerformancePage(pageUri);
    break;
case 'home':
    if (document.location.pathname === '/') {
        hackHomePage();
    }
// case 'date'
}
<commit_msg>wrap main statements in a big try / catch<commit_after>/* global crel */

let MODAL;

function qsa(selector) {
    return Array.from(document.querySelectorAll(selector));
}

function insertBefore(newNode, target) {
    target.parentElement.insertBefore(newNode, target);
}

function buildModal() {
    let closeBtn1, closeBtn2;
    const modalNode = crel(
        'div', {id: 'sparqlit-modal',
                'class': 'modal fade',
                tabindex: -1,
                role: 'dialog',
                'aria-labelledby': 'Sparql-it Modal Dialog'},
        crel('div', {'class': 'modal-dialog', role: 'document'},
             crel('div', {'class': 'modal-content'},
                  crel('div', {'class': 'modal-header'},
                       closeBtn1 = crel('button', {type: 'button',
                                                   'class': 'close',
                                                   'data-dismiss': 'modal',
                                                   'arial-label': 'Close'},
                                        crel('span', {'aria-hidden': true}, 'x')),
                       crel('h4', {'class': 'modal-title',
                                   'id': 'sparql-modal-title'},
                            'SPARQL-it !')),
                  crel('div', {'class': 'modal-body'},
                       crel('pre', {id: 'sparqlit-modal-pre'})),
                  crel('div', {'class': 'modal-footer'},
                       crel('a', {'class': 'btn btn-info',
                                  id: 'sparqlit-modal-exec',
                                  href: '#',
                                  target: '_blank'}, 'Execute'),
                       crel('a', {'class': 'btn btn-info',
                                  id: 'sparqlit-modal-edit',
                                  href: 'http://data.bnf.fr/sparql',
                                  target: '_blank'}, 'Edit'),
                       crel('a', {'class': 'btn btn-info',
                                  id: 'sparqlit-modal-dl',
                                  href: '#',
                                  target: '_blank'}, 'Download (JSON)'),
                       closeBtn2 = crel('button', {type: 'button',
                                                   'class': 'btn btn-default',
                                                   'data-dismiss': 'modal'},
                                        'Close')))));
    closeBtn1.onclick = hideModal;
    closeBtn2.onclick = hideModal;
    return modalNode;
}

function modalBackdrop() {
    return crel('div', {'id': 'sparqlit-modal-backdrop',
                        'class': 'modal-backdrop fade'});
}

function sparqlUrl(query, mimetype) {
    return `http://data.bnf.fr/sparql?query=${encodeURIComponent(query)}&format=${encodeURIComponent(mimetype || 'text/html')}`;
}

function executeQueryLink(querydef) {
    const a = crel('a', {'class': 'sparql-link',
                         target: '_blank',
                         title: 'Execute Query',
                         href: '#'},
                   crel('i', {'class': 'glyphicon glyphicon-search'}),
                   'SPARQL-it');
    a.onclick = (evt) => {showModal(querydef); evt.preventDefault();};
    return a;
}

function sparqlLink(querydef) {
    return crel('span', {'class': 'sparql-it'},
                executeQueryLink(querydef));
}

function authorityMainInfos(pageUri) {
    return {
        title: 'Informations principales',
        query: `
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

SELECT ?uri ?predicate ?object WHERE {

  {
    BIND (<${pageUri}> AS ?uri)
    ?uri ?predicate ?object.
  }

  UNION

  {
    <${pageUri}> foaf:focus ?uri.
    ?uri ?predicate ?object.
  }

}`};
}

function authorDocsQuery(role, authorUri) {
    return {
        title: `Contributions de ${authorUri} avec le rôle ${role}`,
        query:`
PREFIX bnfroles: <http://data.bnf.fr/vocabulary/roles/>
PREFIX rdarelationships: <http://rdvocab.info/RDARelationshipsWEMI/>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT DISTINCT ?manif ?work ?title ?date ?type ?gallica WHERE {

  ?expr bnfroles:${role} <${authorUri}#foaf:Person>.
  ?formerexpr owl:sameAs ?expr.
  ?manif rdarelationships:expressionManifested ?formerexpr ;
         dcterms:title ?title
  OPTIONAL {
    ?manif rdarelationships:workManifested ?work.
  }

  OPTIONAL {
    ?manif rdarelationships:electronicReproduction ?gallica.
  }

  OPTIONAL {
    ?manif dcterms:date ?date.
  }

  OPTIONAL {
    ?formerexpr dcterms:type ?type.
  }

}`};
}

function workDocsQuery(workUri) {
    return {
        title: `Documents associés à l'œuvre ${workUri}`,
        query: `
PREFIX rdarelationships: <http://rdvocab.info/RDARelationshipsWEMI/>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT DISTINCT ?manif ?title ?date ?type ?gallica WHERE {

  ?manif rdarelationships:workManifested <${workUri}#frbr:Work> ;
         rdarelationships:expressionManifested ?formerexpr ;
         dcterms:title ?title

  OPTIONAL {
    ?manif rdarelationships:electronicReproduction ?gallica.
  }

  OPTIONAL {
    ?manif dcterms:date ?date.
  }

  OPTIONAL {
    ?formerexpr dcterms:type ?type.
  }
}`};
}

function relatedAuthorsQuery(authorUri) {
    return {
        title: `Auteurs reliés à ${authorUri}`,
        query: `
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX bnfroles: <http://data.bnf.fr/vocabulary/roles/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

SELECT ?role1 ?manif ?title ?role2 ?author2 ?author2name WHERE {
  ?expr dcterms:contributor <${authorUri}#foaf:Person> ;
        ?role1 <${authorUri}#foaf:Person> ;
        ?role2 ?author2.

  ?author2 a foaf:Person;
       foaf:name ?author2name.

  ?formerexpr owl:sameAs ?expr.
  ?manif rdarelationships:expressionManifested ?formerexpr ;
         dcterms:title ?title.

  FILTER(regex(?role1, 'http://data.bnf.fr/vocabulary/roles'))
  FILTER(regex(?role2, 'http://data.bnf.fr/vocabulary/roles'))
  FILTER(?author2 != <${authorUri}#foaf:Person>)
}`};
}

function placesQuery() {
    return {
        title: 'Lieux documentés dans databnf',
        query: `
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX geo: <http://www.w3.org/2003/01/geo/wgs84_pos#>

SELECT ?geo ?label ?lat ?lng ?geonames WHERE {

  ?geoconcept skos:closeMatch ?rameau ;
    skos:prefLabel ?label ;
    foaf:focus ?geo.

  OPTIONAL {
    ?geoconcept skos:exactMatch ?geonames.
    FILTER(regex(?geonames, 'http://sws.geonames.org/'))
  }

  ?geo geo:lat ?lat ;
       geo:long ?lng.

  ?rameau a skos:Concept.
}
`};
}

function studyDocsQuery(authorityUri) {
    return {
        title: `Documents au sujet de ${authorityUri}`,
        query: `
PREFIX rdarelationships: <http://rdvocab.info/RDARelationshipsWEMI/>
PREFIX dcterms: <http://purl.org/dc/terms/>

SELECT DISTINCT ?manif ?work ?title ?date ?type ?gallica WHERE {

  ?formerexpr owl:sameAs ?expr.

  ?manif dcterms:subject <${authorityUri}> ;
         rdarelationships:expressionManifested ?formerexpr ;
         dcterms:title ?title.

  OPTIONAL {
    ?manif rdarelationships:workManifested ?work.
  }

  OPTIONAL {
    ?manif rdarelationships:electronicReproduction ?gallica.
  }

  OPTIONAL {
    ?manif dcterms:date ?date.
  }

  OPTIONAL {
    ?formerexpr dcterms:type ?type.
  }

}`};
}

function authorWorksQuery(authorUri) {
    return {
        title: `Œuvres de ${authorUri}`,
        query: `
PREFIX dcterms: <http://purl.org/dc/terms/>
PREFIX rdarelationships: <http://rdvocab.info/RDARelationshipsWEMI/>

SELECT ?work ?title (COUNT(?manif) as ?count) WHERE {
 ?work dcterms:creator <${authorUri}#foaf:Person>;
    dcterms:title ?title.

  ?manif rdarelationships:workManifested ?work.
}
GROUP BY ?work ?title
ORDER BY DESC(?count)
`};
}

function storeQuery(query) {
    if (window.localStorage !== undefined) {
        localStorage.setItem('queryVal_main', JSON.stringify({val: query}));
    }
}

function hackMainInfos(pageUri) {
    const h1 = document.querySelector('h1');
    insertBefore(sparqlLink(authorityMainInfos(pageUri)), h1.firstChild);
}

function hackAuthorDocumentSections(authorUri) {
    qsa('.dtmanifs > h3 > a:first-child').forEach(link => {
        const role = link.href.split('/').pop();
        const h3 = link.parentElement;
        h3.insertBefore(sparqlLink(authorDocsQuery(role, authorUri)), link);
    });
}

function hackRelatedAuthors(authorUri) {
    qsa(`.bloc-contenu a[href="http://data.bnf.fr/linked-authors/${authorUri.slice(32, 40)}"]`).forEach(a => {
        insertBefore(sparqlLink(relatedAuthorsQuery(authorUri)), a);
    });
}

function hackAuthorTitle(authorUri) {
    const div = document.querySelector('#allmanifs');
    insertBefore(sparqlLink(authorWorksQuery(authorUri)), div.firstChild);
}

function hackAuthorPage(pageUri) {
    hackMainInfos(pageUri);
    hackAuthorDocumentSections(pageUri);
    hackRelatedAuthors(pageUri);
    hackStudiesSection(pageUri);
    hackAuthorTitle(pageUri);
}

function hackWorkDocumentSections(workUri) {
    qsa('.dtmanifs > h3').forEach(h3 => {
        h3.insertBefore(sparqlLink(workDocsQuery(workUri)), h3.firstChild);
    });
}

function hackStudiesSection(pageUri) {
    qsa('.bloc-contenu a[href$=studies').forEach(link => {
        insertBefore(sparqlLink(studyDocsQuery(pageUri)), link);
    });
}

function hackGeoDocumentSections(geoUri) {
    qsa('.dtmanifs > h3').forEach(h3 => {
        h3.insertBefore(sparqlLink(studyDocsQuery(geoUri)), h3.firstChild);
    });
}

function hackWorkPage(pageUri) {
    hackMainInfos(pageUri);
    hackWorkDocumentSections(pageUri);
    hackStudiesSection(pageUri);
}

function hackGeoPage(pageUri) {
    hackMainInfos(pageUri);
    hackGeoDocumentSections(pageUri);
}

function hackPeriodicalPage(pageUri) {
    hackMainInfos(pageUri);
}

function hackSubjectPage(pageUri) {
    hackMainInfos(pageUri);
}

function hackPerformancePage(pageUri) {
    hackMainInfos(pageUri);
}

function hackHomePage() {
    const mapBlock = document.querySelector('#map-geo');
    insertBefore(sparqlLink(placesQuery()), mapBlock);
}

function guessPageType() {
    const ogtype = document.querySelector('meta[property="og:type"]');
    if (ogtype && ogtype.content) {
        return ogtype.content;
    }
    const path = document.location.pathname;
    if (path === '/') {
        return 'home';
    } else if (path.startsWith('/date')) {
        return 'date';
    } else if (path.startsWith('/3') || path.startsWith('/4')) {
        const divtype = document.querySelector('#fullpage div[itemtype]'),
              itemtype = divtype ? divtype.getAttribute('itemtype') : null;
        if (itemtype === 'http://schema.org/Periodical') {
            return 'periodical';
        } else if (itemtype === 'http://schema.org/TheaterEvent') {
            return 'performance';
        }
    }
    return null;
}

function showModal(querydef) {
    const {query, title} = querydef;
    if (!MODAL) {
        MODAL = buildModal();
        document.body.appendChild(MODAL);
    }
    const backdrop = modalBackdrop();
    document.body.appendChild(backdrop);
    backdrop.classList.add('in');
    MODAL.style.display = 'block';
    MODAL.classList.add('fade', 'in');
    MODAL.querySelector('#sparql-modal-title').textContent = title || 'SPARQL-it !';
    MODAL.querySelector('#sparqlit-modal-pre').textContent = query;
    MODAL.querySelector('#sparqlit-modal-exec').href = sparqlUrl(query);
    MODAL.querySelector('#sparqlit-modal-dl').href = sparqlUrl(query, 'application/sparql-results+json');
    MODAL.querySelector('#sparqlit-modal-edit').onclick = () => storeQuery(query);
}

function hideModal() {
    const backdrop = document.querySelector('#sparqlit-modal-backdrop');
    backdrop.parentNode.removeChild(backdrop);
    MODAL.classList.remove('fade', 'in');
    MODAL.style.display = 'none';
}

try {
    let permalink = document.querySelector('link[rel=bookmark]'),
        pageUri = (permalink === null) ? null : permalink.href;

    switch(guessPageType()) {
    case 'author':
        hackAuthorPage(pageUri);
        break;
    case 'book':
        hackWorkPage(pageUri);
        break;
    case 'geopoint':
        hackGeoPage(pageUri);
        break;
    case 'periodical':
        hackPeriodicalPage(pageUri);
        break;
    case 'article':
        hackSubjectPage(pageUri);
        break;
    case 'performance':
        hackPerformancePage(pageUri);
        break;
    case 'home':
        if (document.location.pathname === '/') {
            hackHomePage();
        }
        // case 'date'
    }
} catch(err) {
    console.log('failed to activate sparql-it extension because', err);
}
<|endoftext|>


<commit_before>define(['text!./filter-report.html', 'app', 'lodash','angular','jquery'], function(template, app, _,angular,$) { 'use strict';

app.directive('filterReport',['$http','Thesaurus','$timeout', function ($http,thesaurus,$timeout) {
    return {
        restrict: 'EAC',
        template: template,
        replace: true,
        require : '^reportingDisplay',
        scope: {
              title: '@title',
              items: '=ngModel',
              facet: '@facet',
              count: '=count' // total count of all children subquires needed for 0 result combinations
        },
          link : function ($scope, $element, $attr, reportingDisplayCtrl)
        {
            $scope.expanded = false;
            var termsMap =[];
            $scope.termsModal = {};

            $scope.terms = [{
              id: '272B0A17-5569-429D-ADF5-2A55C588F7A7',
              title: '5th National Report',
              count:0,
              selected: false
            }, {
              id: 'DA7E04F1-D2EA-491E-9503-F7923B1FD7D4',
              title: '4th National Report',
              count:0,
              selected: false
            }, {
              id: 'A49393CA-2950-4EFD-8BCC-33266D69232F',
              title: '3rd National Report',
              count:0,
              selected: false
            }, {
              id: 'F27DBC9B-FF25-471B-B624-C0F73E76C8B3',
              title: '2nd National Report',
              count:0,
              selected: false
            }, {
              id: '5471756B-6B33-46AD-9D51-15443C5E5315',
              title: '1st National Report',
              count:0,
              selected: false
            }];

            $scope.$watch('items',function(){reportingDisplayCtrl.updateTerms(termsMap,$scope.items,$scope.facet);});

            //=======================================================================
            //
            //=======================================================================
            function buildTermsAndQuery() {

              $scope.terms = searchCtrl.updateTerms($scope.terms,$scope.items,$scope.facet);
              searchCtrl.buildChildQuery($scope.terms,$scope.items,$scope.facet);
            }//buildTermsAndQuery()

            //============================================================
        		//
        		//
        		//============================================================
        		function getAichiTargets() {

          			var  queryParameters = {
          							'q': 'schema_s:nationalReport',
          							'fl': '*',
          							'wt': 'json',
          							'start': 0,
          							'rows': 20,
          			};
          			//return defer;
          			return $http.get('https://api.cbd.int/api/v2013/index/select', { params: queryParameters, cache:true })				.then(function (data) {
                					return {'data':data.data.response.docs};
                });

        		}// getOrganizations

              //=======================================================================
              //
              //=======================================================================
              $scope.loadReports = function (type) {

                if(type)
                    reportingDisplayCtrl.addSubQuery('nationalReport','schema_s:nationalReport AND _latest_s:true AND _state_s:public AND reportType_s:'+type+' ',true);
                else
                    reportingDisplayCtrl.deleteAllSubQuery('nationalReport');
                reportingDisplayCtrl.search();

              };// flatten

        }//link
    }; // return
  }]);  //app.directive('searchFilterCountries
});// define
<commit_msg>Fix mismatch title and actual reports queried<commit_after>define(['text!./filter-report.html', 'app', 'lodash','angular','jquery'], function(template, app, _,angular,$) { 'use strict';

app.directive('filterReport',['$http','Thesaurus','$timeout', function ($http,thesaurus,$timeout) {
    return {
        restrict: 'EAC',
        template: template,
        replace: true,
        require : '^reportingDisplay',
        scope: {
              title: '@title',
              items: '=ngModel',
              facet: '@facet',
              count: '=count' // total count of all children subquires needed for 0 result combinations
        },
          link : function ($scope, $element, $attr, reportingDisplayCtrl)
        {
            $scope.expanded = false;
            var termsMap =[];
            $scope.termsModal = {};

            $scope.terms = [{
              id: 'B3079A36-32A3-41E2-BDE0-65E4E3A51601',
              title: '5th National Report',
              count:0,
              selected: 0
            }, {
              id: '272B0A17-5569-429D-ADF5-2A55C588F7A7',
              title: '4th National Report',
              count:0,
              selected: 0
            }, {
              id: 'DA7E04F1-D2EA-491E-9503-F7923B1FD7D4',
              title: '3rd National Report',
              count:0,
              selected: 0
            }, {
              id: 'A49393CA-2950-4EFD-8BCC-33266D69232F',
              title: '2nd National Report',
              count:0,
              selected: 0
            }, {
              id: 'F27DBC9B-FF25-471B-B624-C0F73E76C8B3',
              title: '1st National Report',
              count:0,
              selected: 0
            }];

            $scope.$watch('items',function(){reportingDisplayCtrl.updateTerms(termsMap,$scope.items,$scope.facet);});

            //=======================================================================
            //
            //=======================================================================
            function buildTermsAndQuery() {

              $scope.terms = searchCtrl.updateTerms($scope.terms,$scope.items,$scope.facet);
              searchCtrl.buildChildQuery($scope.terms,$scope.items,$scope.facet);
            }//buildTermsAndQuery()

            //=======================================================================
            //
            //=======================================================================
            $scope.termsNotSelected = function () {
                  _.each($scope.terms, function (term) {
                      term.selected=0;
                  });
            }//buildTermsAndQuery()

            //============================================================
        		//
        		//
        		//============================================================
        		function getAichiTargets() {

          			var  queryParameters = {
          							'q': 'schema_s:nationalReport',
          							'fl': '*',
          							'wt': 'json',
          							'start': 0,
          							'rows': 20,
          			};
          			//return defer;
          			return $http.get('https://api.cbd.int/api/v2013/index/select', { params: queryParameters, cache:true })				.then(function (data) {
                					return {'data':data.data.response.docs};
                });

        		}// getOrganizations

              //=======================================================================
              //
              //=======================================================================
              $scope.loadReports = function (type) {

                if(type)
                    reportingDisplayCtrl.addSubQuery('nationalReport','schema_s:nationalReport AND _latest_s:true AND _state_s:public AND reportType_s:'+type+' ',true);
                else
                    reportingDisplayCtrl.deleteAllSubQuery('nationalReport');
                reportingDisplayCtrl.search();

              };// flatten

        }//link
    }; // return
  }]);  //app.directive('searchFilterCountries
});// define
<|endoftext|>


<commit_before>require('../lib/class-extras/Source/Class.Binds.js');

/**
 * Connector: the event binder. By setting connector options in the Class,
 * Classes that implement Connector will be able to bind their events with a target Classes
 * methods and vice versa.
 * @type {Class}
 */

// Make the $boundFn unique
var processFn = function(type, evt, fn, obj){
    if (type == 'string') {
        fn = obj[fn] ? obj.bound(fn) : undefined;
    }

    return fn;
};

var mapSubEvents = function(obj, baseEvt){
    var map = {};

    Object.each(obj, function(val, key){
        /**
         * Set the key as baseEvent if the key is "*",
         * otherwise it will be baseEvent:key
         */
        key = key == '*' ? baseEvt : baseEvt + ':' + key;

        map[key] = val;
    });

    return map;
};

var process = function(methodStr, map, obj){
    Object.each(map, function(methods, evt){
        methods = Array.from(methods);

        methods.each(function(method){
            var type = typeOf(method);

            switch(type){
                case 'object':
                    if (!instanceOf(method, Class)) {
                        process.call(this, methodStr, mapSubEvents(method, evt), obj);
                    }
                    break;
                case 'string':
                case 'function':
                    method = processFn.call(this, type, evt, method, obj);

                    method && this[methodStr](evt, method);
                    break;
            };
        }, this);
    }, this);
};

var curryConnection = function(str){
    var methodStr = str == 'connect' ? 'addEvent' : 'removeEvent';

    return function(obj, twoWay){
        if (obj && typeOf(obj[str]) == 'function') {
            var map = this.options.connector;

            process.call(this, methodStr, map, obj);

            // Connecting is a two way street. Connect/disconnect
            // will first connect/disconnect 'this' with obj's methods. Next
            // it will attempt to connect/disconnect obj with 'this' methods
            // hasConnected will prevent a loop.
            twoWay && obj[str](this, false);
        }

        return this;
    };
};

var Connector = new Class({
    Implements: [Class.Binds],

    // options: {
    //     connector: {
    //         'thisEvent': 'otherObjMethod',
    //         model
    //         'change': 'someMethodName'
    //         'change': function(){},
    //         'change': {
    //             '*': 'updateAll',
    //             'name': 'updateName',
    //             'age': function(){}
    //         },
    //         'change': {
    //              '*': ['someMethod', 'someOtherMethod'],
    //              'name': ['updateName', 'updateFullName']
    //         },
    //         'change': [{'*': ['someMethod']}, {'*': ['someOtherMethod']}],
    //     }
    // },

    connect: curryConnection('connect'),

    disconnect: curryConnection('disconnect')
});

exports.Connector = Connector;<commit_msg>Comments and default to twoway connecting.<commit_after>require('../lib/class-extras/Source/Class.Binds.js');

/**
 * Connector: the event binder. By setting connector options in the Class,
 * Classes that implement Connector will be able to bind their events with a target Classes
 * methods and vice versa.
 * @type {Class}
 */

// Make the $boundFn unique
var processFn = function(type, evt, fn, obj){
    if (type == 'string') {
        fn = obj[fn] ? obj.bound(fn) : undefined;
    }

    return fn;
};

var mapSubEvents = function(obj, baseEvt){
    var map = {};

    Object.each(obj, function(val, key){
        /**
         * Set the key as baseEvent if the key is "*",
         * otherwise it will be baseEvent:key
         */
        key = key == '*' ? baseEvt : baseEvt + ':' + key;

        map[key] = val;
    });

    return map;
};

var process = function(methodStr, map, obj){
    Object.each(map, function(methods, evt){
        methods = Array.from(methods);

        methods.each(function(method){
            var type = typeOf(method);

            switch(type){
                case 'object':
                    if (!instanceOf(method, Class)) {
                        process.call(this, methodStr, mapSubEvents(method, evt), obj);
                    }
                    break;
                case 'string':
                case 'function':
                    method = processFn.call(this, type, evt, method, obj);

                    method && this[methodStr](evt, method);
                    break;
            };
        }, this);
    }, this);
};

var curryConnection = function(str){
    var methodStr = str == 'connect' ? 'addEvent' : 'removeEvent';

    return function(obj, oneWay){
        if (obj && typeOf(obj[str]) == 'function') {
            var map = this.options.connector;

            process.call(this, methodStr, map, obj);

            /**
             * Connecting is a two way street. Connect/disconnect will
             * first connect/disconnect 'this' with obj's methods.
             * Next it will attempt to connect/disconnect obj with 'this' methods
             *
             * oneWay will prevent a loop.
             */
            !oneWay && obj[str](this, true);
        }

        return this;
    };
};

var Connector = new Class({
    Implements: [Class.Binds],

    options: {
        connector: {
            // 'thisEvent': 'otherObjMethod',
            // model
            // 'change': 'someMethodName'
            // 'change': function(){},
            // 'change': {
            //     '*': 'updateAll',
            //     'name': 'updateName',
            //     'age': function(){}
            // },
            // 'change': {
            //      '*': ['someMethod', 'someOtherMethod'],
            //      'name': ['updateName', 'updateFullName']
            // },
            // 'change': [{'*': ['someMethod']}, {'*': ['someOtherMethod']}],
        }
    },

    /**
     * Connect two objects. Two way connect by default. One way connect optional
     * @var obj {Class} The Class to connect with.
     * @var oneWay {Boolean} Optional argument to disable two way connecting.
     */
    connect: curryConnection('connect'),

    /**
     * Disconnect two objects. Two way connect by default. One way connect optional
     * @var obj {Class} The Class to connect with.
     * @var oneWay {Boolean} Optional argument to disable two way connecting.
     */
    disconnect: curryConnection('disconnect')
});

exports.Connector = Connector;<|endoftext|>


<commit_before>"use strict";

var normalizeAs = require('../lib/encoders.js').normalizeAs;
var modes = require('../lib/modes.js');
var hashAs = require('../lib/encoders.js').hashAs;
var xhr = require('../lib/xhr.js');
var binary = require('../lib/binary.js');

var modeToType = {
  "040000": "tree",
  "100644": "blob",  // normal file
  "100655": "blob",  // executable file
  "120000": "blob",  // symlink
  "160000": "commit" // gitlink
};

var encoders = {
  commit: encodeCommit,
  tag: encodeTag,
  tree: encodeTree,
  blob: encodeBlob
};

var decoders = {
  commit: decodeCommit,
  tag: decodeTag,
  tree: decodeTree,
  blob: decodeBlob,
};

var emptyBlob = hashAs("blob", "");
var emptyTree = hashAs("tree", []);

// Implement the js-git object interface using github APIs
module.exports = function (repo, root, accessToken) {

  var apiRequest = xhr(root, accessToken);

  repo.loadAs = loadAs;         // (type, hash) -> value, hash
  repo.saveAs = saveAs;         // (type, value) -> hash, value
  repo.readRef = readRef;       // (ref) -> hash
  repo.updateRef = updateRef;   // (ref, hash) -> hash
  repo.createTree = createTree; // (entries) -> hash, tree

  function loadAs(type, hash, callback) {
    // Github doesn't like empty trees, but we know them already.
    if (type === "tree" && hash === emptyTree) return callback(null, {}, hash);
    apiRequest("GET", "/repos/:root/git/" + type + "s/" + hash, onValue);

    function onValue(err, xhr, result) {
      if (err) return callback(err);
      if (xhr.status < 200 || xhr.status >= 500) {
        return callback(new Error("Invalid HTTP response: " + xhr.status + " " + result.message));
      }
      if (xhr.status >= 300 && xhr.status < 500) return callback();
      var body;
      try { body = decoders[type].call(repo, result); }
      catch (err) { return callback(err); }
      if (hashAs(type, body) !== hash) {
        if (fixDate(type, body, hash)) console.log(type + " repaired", hash);
        else console.warn("Unable to repair " + type, hash);
      }
      return callback(null, body, hash);
    }
  }

  function saveAs(type, body, callback) {
    var request;
    try {
      body = normalizeAs(type, body);
      request = encoders[type](body);
    }
    catch (err) {
      return callback(err);
    }

    // Github doesn't allow creating empty trees.
    if (type === "tree" && request.tree.length === 0) {
      return callback(null, emptyTree, body);
    }
    return apiRequest("POST", "/repos/:root/git/" + type + "s", request, onWrite);

    function onWrite(err, xhr, result) {
      if (err) return callback(err);
      if (xhr.status < 200 || xhr.status >= 300) {
        return callback(new Error("Invalid HTTP response: " + xhr.status + " " + result.message));
      }
      return callback(null, result.sha, body);
    }
  }

  // Create a tree with optional deep paths and create new blobs.
  // Entries is an array of {mode, path, hash|content}
  // Also deltas can be specified by setting entries.base to the hash of a tree
  // in delta mode, entries can be removed by specifying just {path}
  function createTree(entries, callback) {
    var toDelete = entries.base && entries.filter(function (entry) {
      return !entry.mode;
    }).map(function (entry) {
      return entry.path;
    });
    if (toDelete && toDelete.length) return slowUpdateTree(entries, toDelete, callback);
    return fastUpdateTree(entries, callback);
  }

  function fastUpdateTree(entries, callback) {
    var request = { tree: entries.map(mapTreeEntry) };
    if (entries.base) request.base_tree = entries.base;

    apiRequest("POST", "/repos/:root/git/trees", request, onWrite);

    function onWrite(err, xhr, result) {
      if (err) return callback(err);
      if (xhr.status < 200 || xhr.status >= 300) {
        return callback(new Error("Invalid HTTP response: " + xhr.status + " " + result.message));
      }
      return callback(null, result.sha, decoders.tree(result));
    }
  }

  // Github doesn't support deleting entries via the createTree API, so we
  // need to manually create those affected trees and modify the request.
  function slowUpdateTree(entries, toDelete, callback) {
    callback = singleCall(callback);
    var root = entries.base;

    var left = 0;

    // Calculate trees that need to be re-built and save any provided content.
    var parents = {};
    toDelete.forEach(function (path) {
      var parentPath = path.substr(0, path.lastIndexOf("/"));
      var parent = parents[parentPath] || (parents[parentPath] = {
        add: {}, del: []
      });
      var name = path.substr(path.lastIndexOf("/") + 1);
      parent.del.push(name);
    });
    var other = entries.filter(function (entry) {
      if (!entry.mode) return false;
      var parentPath = entry.path.substr(0, entry.path.lastIndexOf("/"));
      var parent = parents[parentPath];
      if (!parent) return true;
      var name = entry.path.substr(entry.path.lastIndexOf("/") + 1);
      if (entry.hash) {
        parent.add[name] = {
          mode: entry.mode,
          hash: entry.hash
        };
        return false;
      }
      left++;
      repo.saveAs("blob", entry.content, function(err, hash) {
        if (err) return callback(err);
        parent.add[name] = {
          mode: entry.mode,
          hash: hash
        };
        if (!--left) onParents();
      });
      return false;
    });
    if (!left) onParents();

    function onParents() {
      Object.keys(parents).forEach(function (parentPath) {
        left++;
        // TODO: remove this dependency on pathToEntry
        repo.pathToEntry(root, parentPath, function (err, entry) {
          if (err) return callback(err);
          var tree = entry.tree;
          var commands = parents[parentPath];
          commands.del.forEach(function (name) {
            delete tree[name];
          });
          for (var name in commands.add) {
            tree[name] = commands.add[name];
          }
          repo.saveAs("tree", tree, function (err, hash, tree) {
            if (err) return callback(err);
            other.push({
              path: parentPath,
              hash: hash,
              mode: modes.tree
            });
            if (!--left) {
              other.base = entries.base;
              if (other.length === 1 && other[0].path === "") {
                return callback(null, hash, tree);
              }
              fastUpdateTree(other, callback);
            }
          });
        });
      });
    }
  }

  function readRef(ref, callback) {
    if (!(/^refs\//).test(ref)) {
      return callback(new TypeError("Invalid ref: " + ref));
    }
    return apiRequest("GET", "/repos/:root/git/" + ref, onRef);

    function onRef(err, xhr, result) {
      if (err) return callback(err);
      if (xhr.status === 404) return callback();
      if (xhr.status < 200 || xhr.status >= 300) {
        return callback(new Error("Invalid HTTP response: " + xhr.status + " " + result.message));
      }
      return callback(null, result.object.sha);
    }
  }

  function updateRef(ref, hash, callback) {
    if (!(/^refs\//).test(ref)) {
      return callback(new Error("Invalid ref: " + ref));
    }
    return apiRequest("PATCH", "/repos/:root/git/" + ref, {
      sha: hash
    }, onResult);

    function onResult(err, xhr, result) {
      if (err) return callback(err);
      if (xhr.status === 422 && result.message === "Reference does not exist") {
        return apiRequest("POST", "/repos/:root/git/refs", {
          ref: ref,
          sha: hash
        }, onResult);
      }
      if (xhr.status < 200 || xhr.status >= 300) {
        return callback(new Error("Invalid HTTP response: " + xhr.status + " " + result.message));
      }
      if (err) return callback(err);
      callback(null, hash);
    }

  }

};

// GitHub has a nasty habit of stripping whitespace from messages and loosing
// the timezone.  This information is required to make our hashes match up, so
// we guess it by mutating the value till the hash matches.
// If we're unable to match, we will just force the hash when saving to the cache.
function fixDate(type, value, hash) {
  if (type !== "commit" && type !== "tag") return;
  // Add up to 2 extra newlines and try all 30-minutes timezone offsets.
  for (var x = 0; x < 3; x++) {
    for (var i = -720; i < 720; i += 30) {
      if (type === "commit") {
        value.author.date.timezoneOffset = i;
        value.committer.date.timezoneOffset = i;
      }
      else if (type === "tag") {
        value.tagger.date.timezoneOffset = i;
      }
      if (hash === hashAs(type, value)) return true;
    }
    value.message += "\n";
  }
  // Guessing failed, remove the temporary offset.
  if (type === "commit") {
    delete value.author.date.timezoneOffset;
    delete value.committer.date.timezoneOffset;
  }
  else if (type === "tag") {
    delete value.tagger.date.timezoneOffset;
  }
}

function mapTreeEntry(entry) {
  if (!entry.mode) throw new TypeError("Invalid entry");
  var mode = modeToString(entry.mode);
  var item = {
    path: entry.path,
    mode: mode,
    type: modeToType[mode]
  };
  // Magic hash for empty file since github rejects empty contents.
  if (entry.content === "") entry.hash = emptyBlob;

  if (entry.hash) item.sha = entry.hash;
  else item.content = entry.content;
  return  item;
}

function encodeCommit(commit) {
  var out = {};
  out.message = commit.message;
  out.tree = commit.tree;
  if (commit.parents) out.parents = commit.parents;
  else if (commit.parent) out.parents = [commit.parent];
  else commit.parents = [];
  if (commit.author) out.author = encodePerson(commit.author);
  if (commit.committer) out.committer = encodePerson(commit.committer);
  return out;
}

function encodeTag(tag) {
  return {
    tag: tag.tag,
    message: tag.message,
    object: tag.object,
    tagger: encodePerson(tag.tagger)
  };
}

function encodePerson(person) {
  return {
    name: person.name,
    email: person.email,
    date: (person.date || new Date()).toISOString()
  };
}

function encodeTree(tree) {
  return {
    tree: Object.keys(tree).map(function (name) {
      var entry = tree[name];
      var mode = modeToString(entry.mode);
      return {
        path: name,
        mode: mode,
        type: modeToType[mode],
        sha: entry.hash
      };
    })
  };
}

function encodeBlob(blob) {
  if (typeof blob === "string") return {
    content: binary.encodeUtf8(blob),
    encoding: "utf-8"
  };
  if (binary.isBinary(blob)) return {
    content: binary.toBase64(blob),
    encoding: "base64"
  };
  throw new TypeError("Invalid blob type, must be binary of string");
}

function modeToString(mode) {
  var string = mode.toString(8);
  // Github likes all modes to be 6 chars long
  if (string.length === 5) string = "0" + string;
  return string;
}

function decodeCommit(result) {
  return {
    tree: result.tree.sha,
    parents: result.parents.map(function (object) {
      return object.sha;
    }),
    author: pickPerson(result.author),
    committer: pickPerson(result.committer),
    message: result.message
  };
}

function decodeTag(result) {
  return {
    object: result.object.sha,
    type: result.object.type,
    tag: result.tag,
    tagger: pickPerson(result.tagger),
    message: result.message
  };
}

function decodeTree(result) {
  var tree = {};
  result.tree.forEach(function (entry) {
    tree[entry.path] = {
      mode: parseInt(entry.mode, 8),
      hash: entry.sha
    };
  });
  return tree;
}

function decodeBlob(result) {
  if (result.encoding === 'base64') {
    return binary.fromBase64(result.content.replace(/\n/g, ''));
  }
  if (result.encoding === 'utf-8') {
    return binary.fromUtf8(result.content);
  }
  throw new Error("Unknown blob encoding: " + result.encoding);
}

function pickPerson(person) {
  return {
    name: person.name,
    email: person.email,
    date: parseDate(person.date)
  };
}

function parseDate(string) {
  // TODO: test this once GitHub adds timezone information
  var match = string.match(/(-?)([0-9]{2}):([0-9]{2})$/);
  var date = new Date(string);
  date.timezoneOffset = 0;
  if (match) {
    date.timezoneOffset = (match[1] === "-" ? 1 : -1) * (
      parseInt(match[2], 10) * 60 + parseInt(match[3], 10)
    );
  }
  return date;
}

function singleCall(callback) {
  var done = false;
  return function () {
    if (done) return console.warn("Discarding extra callback");
    done = true;
    return callback.apply(this, arguments);
  };
}
<commit_msg>Fix mode for executable files<commit_after>"use strict";

var normalizeAs = require('../lib/encoders.js').normalizeAs;
var modes = require('../lib/modes.js');
var hashAs = require('../lib/encoders.js').hashAs;
var xhr = require('../lib/xhr.js');
var binary = require('../lib/binary.js');

var modeToType = {
  "040000": "tree",
  "100644": "blob",  // normal file
  "100755": "blob",  // executable file
  "120000": "blob",  // symlink
  "160000": "commit" // gitlink
};

var encoders = {
  commit: encodeCommit,
  tag: encodeTag,
  tree: encodeTree,
  blob: encodeBlob
};

var decoders = {
  commit: decodeCommit,
  tag: decodeTag,
  tree: decodeTree,
  blob: decodeBlob,
};

var emptyBlob = hashAs("blob", "");
var emptyTree = hashAs("tree", []);

// Implement the js-git object interface using github APIs
module.exports = function (repo, root, accessToken) {

  var apiRequest = xhr(root, accessToken);

  repo.loadAs = loadAs;         // (type, hash) -> value, hash
  repo.saveAs = saveAs;         // (type, value) -> hash, value
  repo.readRef = readRef;       // (ref) -> hash
  repo.updateRef = updateRef;   // (ref, hash) -> hash
  repo.createTree = createTree; // (entries) -> hash, tree

  function loadAs(type, hash, callback) {
    // Github doesn't like empty trees, but we know them already.
    if (type === "tree" && hash === emptyTree) return callback(null, {}, hash);
    apiRequest("GET", "/repos/:root/git/" + type + "s/" + hash, onValue);

    function onValue(err, xhr, result) {
      if (err) return callback(err);
      if (xhr.status < 200 || xhr.status >= 500) {
        return callback(new Error("Invalid HTTP response: " + xhr.status + " " + result.message));
      }
      if (xhr.status >= 300 && xhr.status < 500) return callback();
      var body;
      try { body = decoders[type].call(repo, result); }
      catch (err) { return callback(err); }
      if (hashAs(type, body) !== hash) {
        if (fixDate(type, body, hash)) console.log(type + " repaired", hash);
        else console.warn("Unable to repair " + type, hash);
      }
      return callback(null, body, hash);
    }
  }

  function saveAs(type, body, callback) {
    var request;
    try {
      body = normalizeAs(type, body);
      request = encoders[type](body);
    }
    catch (err) {
      return callback(err);
    }

    // Github doesn't allow creating empty trees.
    if (type === "tree" && request.tree.length === 0) {
      return callback(null, emptyTree, body);
    }
    return apiRequest("POST", "/repos/:root/git/" + type + "s", request, onWrite);

    function onWrite(err, xhr, result) {
      if (err) return callback(err);
      if (xhr.status < 200 || xhr.status >= 300) {
        return callback(new Error("Invalid HTTP response: " + xhr.status + " " + result.message));
      }
      return callback(null, result.sha, body);
    }
  }

  // Create a tree with optional deep paths and create new blobs.
  // Entries is an array of {mode, path, hash|content}
  // Also deltas can be specified by setting entries.base to the hash of a tree
  // in delta mode, entries can be removed by specifying just {path}
  function createTree(entries, callback) {
    var toDelete = entries.base && entries.filter(function (entry) {
      return !entry.mode;
    }).map(function (entry) {
      return entry.path;
    });
    if (toDelete && toDelete.length) return slowUpdateTree(entries, toDelete, callback);
    return fastUpdateTree(entries, callback);
  }

  function fastUpdateTree(entries, callback) {
    var request = { tree: entries.map(mapTreeEntry) };
    if (entries.base) request.base_tree = entries.base;

    apiRequest("POST", "/repos/:root/git/trees", request, onWrite);

    function onWrite(err, xhr, result) {
      if (err) return callback(err);
      if (xhr.status < 200 || xhr.status >= 300) {
        return callback(new Error("Invalid HTTP response: " + xhr.status + " " + result.message));
      }
      return callback(null, result.sha, decoders.tree(result));
    }
  }

  // Github doesn't support deleting entries via the createTree API, so we
  // need to manually create those affected trees and modify the request.
  function slowUpdateTree(entries, toDelete, callback) {
    callback = singleCall(callback);
    var root = entries.base;

    var left = 0;

    // Calculate trees that need to be re-built and save any provided content.
    var parents = {};
    toDelete.forEach(function (path) {
      var parentPath = path.substr(0, path.lastIndexOf("/"));
      var parent = parents[parentPath] || (parents[parentPath] = {
        add: {}, del: []
      });
      var name = path.substr(path.lastIndexOf("/") + 1);
      parent.del.push(name);
    });
    var other = entries.filter(function (entry) {
      if (!entry.mode) return false;
      var parentPath = entry.path.substr(0, entry.path.lastIndexOf("/"));
      var parent = parents[parentPath];
      if (!parent) return true;
      var name = entry.path.substr(entry.path.lastIndexOf("/") + 1);
      if (entry.hash) {
        parent.add[name] = {
          mode: entry.mode,
          hash: entry.hash
        };
        return false;
      }
      left++;
      repo.saveAs("blob", entry.content, function(err, hash) {
        if (err) return callback(err);
        parent.add[name] = {
          mode: entry.mode,
          hash: hash
        };
        if (!--left) onParents();
      });
      return false;
    });
    if (!left) onParents();

    function onParents() {
      Object.keys(parents).forEach(function (parentPath) {
        left++;
        // TODO: remove this dependency on pathToEntry
        repo.pathToEntry(root, parentPath, function (err, entry) {
          if (err) return callback(err);
          var tree = entry.tree;
          var commands = parents[parentPath];
          commands.del.forEach(function (name) {
            delete tree[name];
          });
          for (var name in commands.add) {
            tree[name] = commands.add[name];
          }
          repo.saveAs("tree", tree, function (err, hash, tree) {
            if (err) return callback(err);
            other.push({
              path: parentPath,
              hash: hash,
              mode: modes.tree
            });
            if (!--left) {
              other.base = entries.base;
              if (other.length === 1 && other[0].path === "") {
                return callback(null, hash, tree);
              }
              fastUpdateTree(other, callback);
            }
          });
        });
      });
    }
  }

  function readRef(ref, callback) {
    if (!(/^refs\//).test(ref)) {
      return callback(new TypeError("Invalid ref: " + ref));
    }
    return apiRequest("GET", "/repos/:root/git/" + ref, onRef);

    function onRef(err, xhr, result) {
      if (err) return callback(err);
      if (xhr.status === 404) return callback();
      if (xhr.status < 200 || xhr.status >= 300) {
        return callback(new Error("Invalid HTTP response: " + xhr.status + " " + result.message));
      }
      return callback(null, result.object.sha);
    }
  }

  function updateRef(ref, hash, callback) {
    if (!(/^refs\//).test(ref)) {
      return callback(new Error("Invalid ref: " + ref));
    }
    return apiRequest("PATCH", "/repos/:root/git/" + ref, {
      sha: hash
    }, onResult);

    function onResult(err, xhr, result) {
      if (err) return callback(err);
      if (xhr.status === 422 && result.message === "Reference does not exist") {
        return apiRequest("POST", "/repos/:root/git/refs", {
          ref: ref,
          sha: hash
        }, onResult);
      }
      if (xhr.status < 200 || xhr.status >= 300) {
        return callback(new Error("Invalid HTTP response: " + xhr.status + " " + result.message));
      }
      if (err) return callback(err);
      callback(null, hash);
    }

  }

};

// GitHub has a nasty habit of stripping whitespace from messages and loosing
// the timezone.  This information is required to make our hashes match up, so
// we guess it by mutating the value till the hash matches.
// If we're unable to match, we will just force the hash when saving to the cache.
function fixDate(type, value, hash) {
  if (type !== "commit" && type !== "tag") return;
  // Add up to 2 extra newlines and try all 30-minutes timezone offsets.
  for (var x = 0; x < 3; x++) {
    for (var i = -720; i < 720; i += 30) {
      if (type === "commit") {
        value.author.date.timezoneOffset = i;
        value.committer.date.timezoneOffset = i;
      }
      else if (type === "tag") {
        value.tagger.date.timezoneOffset = i;
      }
      if (hash === hashAs(type, value)) return true;
    }
    value.message += "\n";
  }
  // Guessing failed, remove the temporary offset.
  if (type === "commit") {
    delete value.author.date.timezoneOffset;
    delete value.committer.date.timezoneOffset;
  }
  else if (type === "tag") {
    delete value.tagger.date.timezoneOffset;
  }
}

function mapTreeEntry(entry) {
  if (!entry.mode) throw new TypeError("Invalid entry");
  var mode = modeToString(entry.mode);
  var item = {
    path: entry.path,
    mode: mode,
    type: modeToType[mode]
  };
  // Magic hash for empty file since github rejects empty contents.
  if (entry.content === "") entry.hash = emptyBlob;

  if (entry.hash) item.sha = entry.hash;
  else item.content = entry.content;
  return  item;
}

function encodeCommit(commit) {
  var out = {};
  out.message = commit.message;
  out.tree = commit.tree;
  if (commit.parents) out.parents = commit.parents;
  else if (commit.parent) out.parents = [commit.parent];
  else commit.parents = [];
  if (commit.author) out.author = encodePerson(commit.author);
  if (commit.committer) out.committer = encodePerson(commit.committer);
  return out;
}

function encodeTag(tag) {
  return {
    tag: tag.tag,
    message: tag.message,
    object: tag.object,
    tagger: encodePerson(tag.tagger)
  };
}

function encodePerson(person) {
  return {
    name: person.name,
    email: person.email,
    date: (person.date || new Date()).toISOString()
  };
}

function encodeTree(tree) {
  return {
    tree: Object.keys(tree).map(function (name) {
      var entry = tree[name];
      var mode = modeToString(entry.mode);
      return {
        path: name,
        mode: mode,
        type: modeToType[mode],
        sha: entry.hash
      };
    })
  };
}

function encodeBlob(blob) {
  if (typeof blob === "string") return {
    content: binary.encodeUtf8(blob),
    encoding: "utf-8"
  };
  if (binary.isBinary(blob)) return {
    content: binary.toBase64(blob),
    encoding: "base64"
  };
  throw new TypeError("Invalid blob type, must be binary of string");
}

function modeToString(mode) {
  var string = mode.toString(8);
  // Github likes all modes to be 6 chars long
  if (string.length === 5) string = "0" + string;
  return string;
}

function decodeCommit(result) {
  return {
    tree: result.tree.sha,
    parents: result.parents.map(function (object) {
      return object.sha;
    }),
    author: pickPerson(result.author),
    committer: pickPerson(result.committer),
    message: result.message
  };
}

function decodeTag(result) {
  return {
    object: result.object.sha,
    type: result.object.type,
    tag: result.tag,
    tagger: pickPerson(result.tagger),
    message: result.message
  };
}

function decodeTree(result) {
  var tree = {};
  result.tree.forEach(function (entry) {
    tree[entry.path] = {
      mode: parseInt(entry.mode, 8),
      hash: entry.sha
    };
  });
  return tree;
}

function decodeBlob(result) {
  if (result.encoding === 'base64') {
    return binary.fromBase64(result.content.replace(/\n/g, ''));
  }
  if (result.encoding === 'utf-8') {
    return binary.fromUtf8(result.content);
  }
  throw new Error("Unknown blob encoding: " + result.encoding);
}

function pickPerson(person) {
  return {
    name: person.name,
    email: person.email,
    date: parseDate(person.date)
  };
}

function parseDate(string) {
  // TODO: test this once GitHub adds timezone information
  var match = string.match(/(-?)([0-9]{2}):([0-9]{2})$/);
  var date = new Date(string);
  date.timezoneOffset = 0;
  if (match) {
    date.timezoneOffset = (match[1] === "-" ? 1 : -1) * (
      parseInt(match[2], 10) * 60 + parseInt(match[3], 10)
    );
  }
  return date;
}

function singleCall(callback) {
  var done = false;
  return function () {
    if (done) return console.warn("Discarding extra callback");
    done = true;
    return callback.apply(this, arguments);
  };
}
<|endoftext|>


<commit_before>"use strict";

var encoders = require('../lib/object-codec').encoders;
var decoders = require('../lib/object-codec').decoders;

var cache = memCache.cache = {};
module.exports = memCache;

function memCache(repo) {
  var loadAs = repo.loadAs;
  repo.loadAs = loadAsCached;
  function loadAsCached(type, hash, callback) {
    if (hash in cache) return callback(null, dupe(type, cache[hash]), hash);
    loadAs.call(repo, type, hash, function (err, value) {
      if (value === undefined) return callback(err);
      if (type !== "blob" || value.length < 100) {
        cache[hash] = dupe(type, value);
      }
      return callback.apply(this, arguments);
    });
  }

  var saveAs = repo.saveAs;
  repo.saveAs = saveAsCached;
  function saveAsCached(type, value, callback) {
    value = dupe(type, value);
    saveAs.call(repo, type, value, function (err, hash, value) {
      if (err) return callback(err);
      if (type !== "blob" || value.length < 100) {
        cache[hash] = value;
      }
      return callback(null, hash, value);
    });
  }
}

function dupe(type, value) {
  if (type === "blob") {
    if (type.length >= 100) return value;
    return new Uint8Array(value);
  }
  return decoders[type](encoders[type](value));
}

function deepFreeze(obj) {
  Object.freeze(obj);
  Object.keys(obj).forEach(function (key) {
    var value = obj[key];
    if (typeof value === "object") deepFreeze(value);
  });
}
<commit_msg>Make mem-cache continuable friendly<commit_after>"use strict";

var encoders = require('../lib/object-codec').encoders;
var decoders = require('../lib/object-codec').decoders;

var cache = memCache.cache = {};
module.exports = memCache;

function memCache(repo) {
  var loadAs = repo.loadAs;
  repo.loadAs = loadAsCached;
  function loadAsCached(type, hash, callback) {
    if (!callback) return loadAsCached.bind(this, type, hash);
    if (hash in cache) return callback(null, dupe(type, cache[hash]), hash);
    loadAs.call(repo, type, hash, function (err, value) {
      if (value === undefined) return callback(err);
      if (type !== "blob" || value.length < 100) {
        cache[hash] = dupe(type, value);
      }
      return callback.apply(this, arguments);
    });
  }

  var saveAs = repo.saveAs;
  repo.saveAs = saveAsCached;
  function saveAsCached(type, value, callback) {
    if (!callback) return saveAsCached.bind(this, type, value);
    value = dupe(type, value);
    saveAs.call(repo, type, value, function (err, hash, value) {
      if (err) return callback(err);
      if (type !== "blob" || value.length < 100) {
        cache[hash] = value;
      }
      return callback(null, hash, value);
    });
  }
}

function dupe(type, value) {
  if (type === "blob") {
    if (type.length >= 100) return value;
    return new Uint8Array(value);
  }
  return decoders[type](encoders[type](value));
}

function deepFreeze(obj) {
  Object.freeze(obj);
  Object.keys(obj).forEach(function (key) {
    var value = obj[key];
    if (typeof value === "object") deepFreeze(value);
  });
}
<|endoftext|>


<commit_before>

var WaterfallChartView = BaseChartView.extend({
  initialize : function() {
    this.initialize_defaults();
    this.HEIGHT = '460px';
  },

  render : function() {
    this.clear_container();
    InitializeWaterfall(this.model.get("container"),
      this.results(),
      'PJ', //this.parsed_unit(),
      this.axis_scale_adjusted_with_ticks(),
      this.colors(),
      this.labels(),
      this.number_of_ticks());
  },

  colors : function() {
    var colors = this.model.colors();
    colors.push(colors[0]);
    return colors;
  },

  labels : function() {
    var labels = this.model.labels();
    labels.push(this.model.get('id') == 51 ? App.settings.get("end_year") : 'Total');
    return labels;
  },

  results : function() {
    var series = this.model.series.map(function(serie) {
      var present = serie.result_pairs()[0];
      var future = serie.result_pairs()[1];
      if (serie.get('group') == 'value') {
        return present; // Take only the present value, as group == value queries only future/present
      } else {
        return future - present;
      }
    });

    var start_scale = (this.model.get('id') == 61) ? 2 : 3;

    var scale_sum = Metric.scaled_scale(_.reduce(series, function(sum,n) {return sum + n;}, 0), start_scale);
    var scale_max = Metric.scaled_scale(_.max(series), start_scale);
    // fix the scaling when really small and large numbers are present
    var scale = (scale_sum > scale_max) ? scale_sum : scale_max;
    var series_scaled = _.map(series, function(value) {
      return Metric.scaled_value(value, start_scale, scale);
    });

    return series;
  },

  axis_scale_adjusted_with_ticks : function() {
    var axis_scale = this.axis_scale();
    var ticks = this.ticks();
    var ticks_negative = ticks[0];
    var ticks_positive = ticks[1];
    var tick_size = this.tick_size();

    axis_scale[0] = ticks_negative * tick_size * -1;
    axis_scale[1] = ticks_positive * tick_size;

    return axis_scale;
  },

  ticks : function() {
    var axis_scale = this.axis_scale();
    var min_value = Math.abs(axis_scale[0]);
    var max_value = Math.abs(axis_scale[1]);

    var tick_size = this.tick_size();
    var ticks_negative = min_value == 0 ? 0 : (min_value / tick_size);
    var ticks_positive = max_value == 0 ? 0 : (max_value / tick_size);

    if (ticks_positive + ticks_negative > 10) {
      ticks_negative = ticks_negative / 2;
      ticks_positive = ticks_positive / 2;
      tick_size = tick_size / 2;
    }
    return [ticks_negative, ticks_positive];
  },

  tick_size : function() {
    var axis_scale = this.axis_scale();
    var min_value = Math.abs(axis_scale[0]);
    var max_value = Math.abs(axis_scale[1]);

    var tick_size = this.calculate_tick_size(_.max([min_value, max_value]));
    return tick_size;
  },

  number_of_ticks : function() {
    var ticks = this.ticks();
    var ticks_negative = ticks[0];
    var ticks_positive = ticks[1];

    var total_ticks = ticks_positive + ticks_negative + 1
    return [total_ticks, this.tick_size()];
  },

  calculate_tick_size : function(value) {
    var length = parseInt(Math.log(value) / Math.log(10));
    var divider = Math.pow(10,length);
    var ticks = value / divider;
    if (ticks < 2) { ticks = ticks * 5; }
    return value / ticks;
  }

});
<commit_msg>let the waterfall use actual unit<commit_after>

var WaterfallChartView = BaseChartView.extend({
  initialize : function() {
    this.initialize_defaults();
    this.HEIGHT = '460px';
  },

  render : function() {
    this.clear_container();
    InitializeWaterfall(this.model.get("container"),
      this.results(),
      this.model.get('unit'),
      this.axis_scale_adjusted_with_ticks(),
      this.colors(),
      this.labels(),
      this.number_of_ticks());
  },

  colors : function() {
    var colors = this.model.colors();
    colors.push(colors[0]);
    return colors;
  },

  labels : function() {
    var labels = this.model.labels();
    labels.push(this.model.get('id') == 51 ? App.settings.get("end_year") : 'Total');
    return labels;
  },

  results : function() {
    var series = this.model.series.map(function(serie) {
      var present = serie.result_pairs()[0];
      var future = serie.result_pairs()[1];
      if (serie.get('group') == 'value') {
        return present; // Take only the present value, as group == value queries only future/present
      } else {
        return future - present;
      }
    });

    var start_scale = (this.model.get('id') == 61) ? 2 : 3;

    var scale_sum = Metric.scaled_scale(_.reduce(series, function(sum,n) {return sum + n;}, 0), start_scale);
    var scale_max = Metric.scaled_scale(_.max(series), start_scale);
    // fix the scaling when really small and large numbers are present
    var scale = (scale_sum > scale_max) ? scale_sum : scale_max;
    var series_scaled = _.map(series, function(value) {
      return Metric.scaled_value(value, start_scale, scale);
    });

    return series;
  },

  axis_scale_adjusted_with_ticks : function() {
    var axis_scale = this.axis_scale();
    var ticks = this.ticks();
    var ticks_negative = ticks[0];
    var ticks_positive = ticks[1];
    var tick_size = this.tick_size();

    axis_scale[0] = ticks_negative * tick_size * -1;
    axis_scale[1] = ticks_positive * tick_size;

    return axis_scale;
  },

  ticks : function() {
    var axis_scale = this.axis_scale();
    var min_value = Math.abs(axis_scale[0]);
    var max_value = Math.abs(axis_scale[1]);

    var tick_size = this.tick_size();
    var ticks_negative = min_value == 0 ? 0 : (min_value / tick_size);
    var ticks_positive = max_value == 0 ? 0 : (max_value / tick_size);

    if (ticks_positive + ticks_negative > 10) {
      ticks_negative = ticks_negative / 2;
      ticks_positive = ticks_positive / 2;
      tick_size = tick_size / 2;
    }
    return [ticks_negative, ticks_positive];
  },

  tick_size : function() {
    var axis_scale = this.axis_scale();
    var min_value = Math.abs(axis_scale[0]);
    var max_value = Math.abs(axis_scale[1]);

    var tick_size = this.calculate_tick_size(_.max([min_value, max_value]));
    return tick_size;
  },

  number_of_ticks : function() {
    var ticks = this.ticks();
    var ticks_negative = ticks[0];
    var ticks_positive = ticks[1];

    var total_ticks = ticks_positive + ticks_negative + 1
    return [total_ticks, this.tick_size()];
  },

  calculate_tick_size : function(value) {
    var length = parseInt(Math.log(value) / Math.log(10));
    var divider = Math.pow(10,length);
    var ticks = value / divider;
    if (ticks < 2) { ticks = ticks * 5; }
    return value / ticks;
  }

});
<|endoftext|>


<commit_before>angular.module('module_searchEngine')

/*
 * module_searchEngine_resultTable
 *
 * variable from the directive
 * @param var searchValue
 * @param var orderBy
 * @param int limitTo
 * @param bool activeIMDb
 */
.controller('module_searchEngine_resultTable', function ($scope, webservice_searchEngine, webservice_metadata, service_recognizeMetadata) {

    $scope.searchValueOld = "";
    $scope.result = null;
    $scope.loading = 0;
    $scope.metadata = {};

    $scope.search = function(search) {
        if(search != $scope.searchValueOld) {
            $scope.loading++;
            webservice_searchEngine.search(search).then(function(response) {
                $scope.searchValueOld = search;
                $scope.result = response.data;
                $scope.loading--;

                angular.forEach($scope.result, function(torrent, key) {
                    torrent.recognizeMetadata = service_recognizeMetadata(torrent.title);

                    //add metadata
                    webservice_metadata.getFromRecognizeMetadata(torrent.recognizeMetadata).then(function(data) {
                        torrent.metadata = data;
                    });
                });
            }, function(data) {
                console.log("error", data);
            });
        }
    };

    $scope.$watch(
        function() {
            return $scope.searchValue;
        },
        function() {
            $scope.search($scope.searchValue);
        }
    );
});<commit_msg>Add loading to metadata<commit_after>angular.module('module_searchEngine')

/*
 * module_searchEngine_resultTable
 *
 * variable from the directive
 * @param var searchValue
 * @param var orderBy
 * @param int limitTo
 * @param bool activeIMDb
 */
.controller('module_searchEngine_resultTable', function ($scope, webservice_searchEngine, webservice_metadata, service_recognizeMetadata) {

    var searchValueOld = "";
    $scope.result = null;
    $scope.loading = 0;

    $scope.search = function(search) {
        if(search != $scope.searchValueOld) {
            $scope.loading++;
            webservice_searchEngine.search(search).then(function(response) {
                $scope.searchValueOld = search;
                $scope.result = response.data;
                $scope.loading--;

                angular.forEach($scope.result, function(torrent, key) {
                    torrent.recognizeMetadata = service_recognizeMetadata(torrent.title);

                    //add metadata
                    $scope.loading++;
                    webservice_metadata.getFromRecognizeMetadata(torrent.recognizeMetadata).then(function(data) {
                        $scope.loading--;
                        torrent.metadata = data;
                    });
                });
            }, function(data) {
                console.log("error", data);
            });
        }
    };

    $scope.$watch(
        function() {
            return $scope.searchValue;
        },
        function() {
            $scope.search($scope.searchValue);
        }
    );
});<|endoftext|>


<commit_before>import * as d3 from 'd3';
import * as dc from 'dc'
import {crossfilter, units, geoChoroplethChart, bubbleChart, renderAll, redrawAll, filterAll, pieChart, barChart, dataCount, dataTable, pluck} from 'dc';
import * as colorbrewer from "colorbrewer";
import reductio from "reductio";
//we can call export at the top of the class declaration
export default class ThrashDashDC {

  constructor(el, props = {}) {
    //we initiate charts in constructor
    this.myCharts = ThrashDashDC.initCharts();
  }

  render() {
    //de-structure myCharts object
    let {SFHBubbleChart, SFQBubbleChart, SFCBubbleChart,
           qualityFactorChart, hollowFactorChart , crowdFactorChart,
           funFactorChart, yearChart, monthChart, dayChart} = this.myCharts;

    d3.json('data/thrashtown.json', (error, data) => {
      //format the data
      const surfData = this.formatData(data);
      const ttx = crossfilter(surfData);
      // build the x dimensions
      const xDims = this.buildXDimensions(ttx);
      //destructure the xDims object
      const {qualityFactorDim, hollowFactorDim, crowdFactorDim,
             funFactorDim, yearDim, monthDim, dayDim,
             stickDimQuality, stickDimCrowd, stickDimHollow} = xDims;
      //build the Y groups
      const yGroups = this.buildYGroups(ttx, xDims);
      //de-structure they yGroups object
      const {all, countPerQualityFactor, countPerHollowFactor, countPerCrowdFactor,
             countPerFunFactor, countPerYear, countPerMonth,countPerDay,
             stickGroup} = yGroups;

   SFQBubbleChart = this.buildBubbleChart(SFQBubbleChart, stickDimQuality, stickGroup, "quality", "fun");
   SFHBubbleChart = this.buildBubbleChart(SFHBubbleChart, stickDimHollow, stickGroup, "hollow", "fun");
   SFCBubbleChart = this.buildBubbleChart(SFCBubbleChart, stickDimCrowd, stickGroup, "crowd", "fun");

      qualityFactorChart
        .width(300)
        .height(180)
        .dimension(qualityFactorDim)
        .group(countPerQualityFactor)
        .x(d3.scale.linear().domain([0,5.2]))
        .elasticY(true)
        .centerBar(true)
        .barPadding(5)
        .xAxisLabel('Quality Factor')
        .yAxisLabel('Sessions')
      qualityFactorChart.xAxis().tickValues([0,1,2,3,4,5]);

      hollowFactorChart
        .width(300)
        .height(180)
        .dimension(hollowFactorDim)
        .group(countPerHollowFactor)
        .x(d3.scale.linear().domain([0,5.2]))
        .elasticY(true)
        .centerBar(true)
        .barPadding(5)
        .xAxisLabel('Hollow Factor')
        .yAxisLabel('Sessions')
      hollowFactorChart.xAxis().tickValues([0,1,2,3,4,5]);

      crowdFactorChart
        .width(300)
        .height(180)
        .dimension(crowdFactorDim)
        .group(countPerCrowdFactor)
        .x(d3.scale.linear().domain([0,5.2]))
        .elasticY(true)
        .centerBar(true)
        .barPadding(5)
        .xAxisLabel('Crowd Factor')
        .yAxisLabel('Sessions')
      crowdFactorChart.xAxis().tickValues([0,1,2,3,4,5]);

      funFactorChart
        .width(300)
        .height(180)
        .dimension(funFactorDim)
        .group(countPerFunFactor)
        .x(d3.scale.linear().domain([0,5.2]))
        .elasticY(true)
        .centerBar(true)
        .barPadding(5)
        .xAxisLabel('Fun Factor')
        .yAxisLabel('Sessions')
      funFactorChart.xAxis().tickValues([0, 1, 2, 3, 4, 5]);

      yearChart
        .width(150)
        .height(150)
        .dimension(yearDim)
        .group(countPerYear)
        .innerRadius(20);

      monthChart
        .width(150)
        .height(150)
        .dimension(monthDim)
        .group(countPerMonth)
        .innerRadius(20)
        .ordering((d) => {
          const order = {
            'jan': 1, 'feb': 2, 'mar': 3, 'apr': 4,
            'may': 5, 'jun': 6, 'jul': 7, 'aug': 8,
            'sep': 9, 'oct': 10, 'nov': 11, 'dec': 12
          };
          return order[d.key];
        });

      dayChart
        .width(150)
        .height(150)
        .dimension(dayDim)
        .group(countPerDay)
        .innerRadius(20)
        .ordering((d) => {
          const order = {
            'mon': 0, 'tue': 1, 'wed': 2, 'thu': 3,
            'fri': 4, 'sat': 5, 'sun': 6
          }
          return order[d.key];
        });

      //draw the viz!
      renderAll();

    });
  }

  static initCharts() {
    const SFHBubbleChart = bubbleChart('#chart-bubble-stick-fun-hollow');
    const SFQBubbleChart = bubbleChart('#chart-bubble-stick-fun-quality');
    const SFCBubbleChart = bubbleChart('#chart-bubble-stick-fun-crowd');
    const qualityFactorChart = barChart('#chart-bar-quality-factor');
    const hollowFactorChart = barChart('#chart-bar-hollow-factor');
    const crowdFactorChart = barChart('#chart-bar-crowd-factor');
    const funFactorChart = barChart('#chart-bar-fun-factor');
    const yearChart = pieChart('#chart-ring-year');
    const monthChart = pieChart('#chart-ring-month');
    const dayChart = pieChart('#chart-ring-day');

    const myCharts = {SFHBubbleChart, SFQBubbleChart, SFCBubbleChart,
                      qualityFactorChart, hollowFactorChart , crowdFactorChart,
                      funFactorChart, yearChart, monthChart, dayChart};

    return myCharts;
  }

  resetChart(chartName) {

    let {SFHBubbleChart, SFQBubbleChart, SFCBubbleChart,
         qualityFactorChart, hollowFactorChart , crowdFactorChart,
         funFactorChart, yearChart, monthChart, dayChart} = this.myCharts;

    switch (chartName) {
      case "chart-ring-year":
        yearChart.filterAll();
        break;
      case "chart-ring-month":
        monthChart.filterAll();
        break;
      case "chart-ring-day":
        dayChart.filterAll();
        break;
      case "chart-bar-fun-factor":
        funFactorChart.filterAll();
        break;
      case "chart-bar-crowd-factor":
        crowdFactorChart.filterAll();
        break;
      case "chart-bar-hollow-factor":
        hollowFactorChart.filterAll();
        break;
      case "chart-bar-quality-factor":
        qualityFactorChart.filterAll();
        break;
      default:
        //Statements executed when none of the values match the value of the expression
        break;
    }

    redrawAll();
  }

  buildBubbleChart(chart, dim, group, x, y){
        //console.log(group.top(2));
      chart
        .width(400)
        .height(250)
        .transitionDuration(1500)
        .margins({top:10, right:50, bottom:30, left:40})
        .dimension(dim)
        .group(group)
        .ordinalColors(colorbrewer.Spectral[7])
        .colorAccessor((p) => {
          return p.key;
        })
        .keyAccessor((p) => {
          //return p.value.quality.avg;
          return p.value[x].avg;
        })
        .valueAccessor((p) => {
          return p.value[y].avg;
        })
        .radiusValueAccessor((p) => {
          return p.value.fun.count;
        })
        .maxBubbleRelativeSize(0.2)
        .x(d3.scale.linear().domain([0, 5]))
        .y(d3.scale.linear().domain([0, 5]))
        .r(d3.scale.linear().domain([0, 100]))
        .elasticY(false)
        .elasticX(false)
        .yAxisPadding(100)
        .xAxisPadding(500)
        .renderHorizontalGridLines(true)
        .renderVerticalGridLines(true)
        .xAxisLabel(x)
        .yAxisLabel(y)
        .yAxis().tickFormat(function (v) {
          return v + '%';
        });
    return chart;
  }

  formatData(data){

    const surfData = data;

    const fullDateFormat = d3.time.format("%a, %d %b %Y %X %Z");
    const yearFormat = d3.time.format('%Y');
    const monthFormat = d3.time.format('%b');
    const dayFormat = d3.time.format('%a');

    surfData.forEach(d=>{
      let dateObj  = new Date(d.sessionDate);
      d.sessionDateFormatted = fullDateFormat(dateObj);
      d.sessionYear = +yearFormat(dateObj);
      d.sessionMonth = monthFormat(dateObj);
      d.sessionDay = dayFormat(dateObj);
    });

    return surfData;
  }

  buildXDimensions(ttx){
    // create dimensions (x-axis values)
    const qualityFactorDim  = ttx.dimension(dc.pluck("waveQuality"));
    const hollowFactorDim  = ttx.dimension(dc.pluck("hollowness"));
    const crowdFactorDim  = ttx.dimension(dc.pluck("crowdedness"));
    const funFactorDim  = ttx.dimension(pluck("funFactor"));
    const yearDim  = ttx.dimension(pluck("sessionYear"));
    const monthDim  = ttx.dimension(pluck("sessionMonth"));
    const dayDim  = ttx.dimension(pluck("sessionDay"));
    const stickDimQuality  = ttx.dimension(pluck("board", (x,i) => {
      return x.name;
    }));
    const stickDimCrowd  = ttx.dimension(pluck("board", (x,i) => {
      return x.name;
    }));
    const stickDimHollow  = ttx.dimension(pluck("board", (x,i) => {
      return x.name;
    }));

    const xDims = { qualityFactorDim, hollowFactorDim, crowdFactorDim,
                    funFactorDim, yearDim, monthDim, dayDim,
                    stickDimQuality, stickDimCrowd, stickDimHollow };
    return xDims;

  }

  buildYGroups(ttx, xDims){

    const {qualityFactorDim, hollowFactorDim, crowdFactorDim,
           funFactorDim, yearDim, monthDim, dayDim,
           stickDimQuality, stickDimCrowd, stickDimHollow} = xDims;

    // create groups (y-axis values)
    const all = ttx.groupAll();
    const countPerQualityFactor = qualityFactorDim.group().reduceCount();
    const countPerHollowFactor = hollowFactorDim.group().reduceCount();
    const countPerCrowdFactor = crowdFactorDim.group().reduceCount();
    const countPerFunFactor = funFactorDim.group().reduceCount();
    const countPerYear = yearDim.group().reduceCount();
    const countPerMonth = monthDim.group().reduceCount();
    const countPerDay = dayDim.group().reduceCount();
    //map reduce functions
    let stickGroup = stickDimQuality.group();
    let bReducer = reductio();
    bReducer.value("quality").count(true).sum((d)=>{return d.waveQuality;}).avg(true);
    bReducer.value("fun").count(true).sum((d)=>{return d.funFactor}).avg(true);
    bReducer.value("crowd").count(true).sum((d)=>{return d.crowdedness}).avg(true);
    bReducer.value("hollow").count(true).sum((d)=>{return d.hollowness}).avg(true);
    bReducer(stickGroup);

    const yGroups = {all, countPerQualityFactor, countPerHollowFactor, countPerCrowdFactor,
                     countPerFunFactor, countPerYear, countPerMonth, countPerDay,
                     stickGroup};

    return yGroups;

  }

  //end of class
}
<commit_msg>bar chart refactor<commit_after>import * as d3 from 'd3';
import * as dc from 'dc'
import {crossfilter, units, geoChoroplethChart, bubbleChart, renderAll, redrawAll, filterAll, pieChart, barChart, dataCount, dataTable, pluck} from 'dc';
import * as colorbrewer from "colorbrewer";
import reductio from "reductio";
//we can call export at the top of the class declaration
export default class ThrashDashDC {

  constructor(el, props = {}) {
    //we initiate charts in constructor
    this.myCharts = ThrashDashDC.initCharts();
  }

  render() {
    //de-structure myCharts object
    let {SFHBubbleChart, SFQBubbleChart, SFCBubbleChart,
           QFBarChart, HFBarChart, crowdFactorChart,
           funFactorChart, yearChart, monthChart, dayChart} = this.myCharts;

    d3.json('data/thrashtown.json', (error, data) => {
      //format the data
      const surfData = this.formatData(data);
      const ttx = crossfilter(surfData);
      // build the x dimensions
      const xDims = this.buildXDimensions(ttx);
      //destructure the xDims object
      const {qualityFactorDim, hollowFactorDim, crowdFactorDim,
             funFactorDim, yearDim, monthDim, dayDim,
             stickDimQuality, stickDimCrowd, stickDimHollow} = xDims;
      //build the Y groups
      const yGroups = this.buildYGroups(ttx, xDims);
      //de-structure they yGroups object
      const {all, countPerQualityFactor, countPerHollowFactor, countPerCrowdFactor,
             countPerFunFactor, countPerYear, countPerMonth,countPerDay,
             stickGroup} = yGroups;

   SFQBubbleChart = this.buildBubbleChart(SFQBubbleChart, stickDimQuality, stickGroup, "quality", "fun");
   SFHBubbleChart = this.buildBubbleChart(SFHBubbleChart, stickDimHollow, stickGroup, "hollow", "fun");
   SFCBubbleChart = this.buildBubbleChart(SFCBubbleChart, stickDimCrowd, stickGroup, "crowd", "fun");
   QFBarChart = this.buildBarChart(QFBarChart, qualityFactorDim, countPerQualityFactor,"metric", "quality", "sessions");
   HFBarChart = this.buildBarChart(HFBarChart, hollowFactorDim, countPerHollowFactor,"metric", "hollow", "sessions");
/*      qualityFactorChart
        .width(300)
        .height(180)
        .dimension(qualityFactorDim)
        .group(countPerQualityFactor)
        .x(d3.scale.linear().domain([0,5.2]))
        .elasticY(true)
        .centerBar(true)
        .barPadding(5)
        .xAxisLabel('Quality Factor')
        .yAxisLabel('Sessions')
      qualityFactorChart.xAxis().tickValues([0,1,2,3,4,5]);

      hollowFactorChart
        .width(300)
        .height(180)
        .dimension(hollowFactorDim)
        .group(countPerHollowFactor)
        .x(d3.scale.linear().domain([0,5.2]))
        .elasticY(true)
        .centerBar(true)
        .barPadding(5)
        .xAxisLabel('Hollow Factor')
        .yAxisLabel('Sessions')
      hollowFactorChart.xAxis().tickValues([0,1,2,3,4,5]);*/

      crowdFactorChart
        .width(300)
        .height(180)
        .dimension(crowdFactorDim)
        .group(countPerCrowdFactor)
        .x(d3.scale.linear().domain([0,5.2]))
        .elasticY(true)
        .centerBar(true)
        .barPadding(5)
        .xAxisLabel('Crowd Factor')
        .yAxisLabel('Sessions')
      crowdFactorChart.xAxis().tickValues([0,1,2,3,4,5]);

      funFactorChart
        .width(300)
        .height(180)
        .dimension(funFactorDim)
        .group(countPerFunFactor)
        .x(d3.scale.linear().domain([0,5.2]))
        .elasticY(true)
        .centerBar(true)
        .barPadding(5)
        .xAxisLabel('Fun Factor')
        .yAxisLabel('Sessions')
      funFactorChart.xAxis().tickValues([0, 1, 2, 3, 4, 5]);

      yearChart
        .width(150)
        .height(150)
        .dimension(yearDim)
        .group(countPerYear)
        .innerRadius(20);

      monthChart
        .width(150)
        .height(150)
        .dimension(monthDim)
        .group(countPerMonth)
        .innerRadius(20)
        .ordering((d) => {
          const order = {
            'jan': 1, 'feb': 2, 'mar': 3, 'apr': 4,
            'may': 5, 'jun': 6, 'jul': 7, 'aug': 8,
            'sep': 9, 'oct': 10, 'nov': 11, 'dec': 12
          };
          return order[d.key];
        });

      dayChart
        .width(150)
        .height(150)
        .dimension(dayDim)
        .group(countPerDay)
        .innerRadius(20)
        .ordering((d) => {
          const order = {
            'mon': 0, 'tue': 1, 'wed': 2, 'thu': 3,
            'fri': 4, 'sat': 5, 'sun': 6
          }
          return order[d.key];
        });

      //draw the viz!
      renderAll();

    });
  }

  static initCharts() {
    const SFHBubbleChart = bubbleChart('#chart-bubble-stick-fun-hollow');
    const SFQBubbleChart = bubbleChart('#chart-bubble-stick-fun-quality');
    const SFCBubbleChart = bubbleChart('#chart-bubble-stick-fun-crowd');
    const QFBarChart = barChart('#chart-bar-quality-factor');
    const HFBarChart = barChart('#chart-bar-hollow-factor');
    const crowdFactorChart = barChart('#chart-bar-crowd-factor');
    const funFactorChart = barChart('#chart-bar-fun-factor');
    const yearChart = pieChart('#chart-ring-year');
    const monthChart = pieChart('#chart-ring-month');
    const dayChart = pieChart('#chart-ring-day');

    const myCharts = {SFHBubbleChart, SFQBubbleChart, SFCBubbleChart,
                      QFBarChart, HFBarChart, crowdFactorChart,
                      funFactorChart, yearChart, monthChart, dayChart};

    return myCharts;
  }

  resetChart(chartName) {

    let {SFHBubbleChart, SFQBubbleChart, SFCBubbleChart,
         QFBarChart, HFBarChart, crowdFactorChart,
         funFactorChart, yearChart, monthChart, dayChart} = this.myCharts;

    switch (chartName) {
      case "chart-ring-year":
        yearChart.filterAll();
        break;
      case "chart-ring-month":
        monthChart.filterAll();
        break;
      case "chart-ring-day":
        dayChart.filterAll();
        break;
      case "chart-bar-fun-factor":
        funFactorChart.filterAll();
        break;
      case "chart-bar-crowd-factor":
        crowdFactorChart.filterAll();
        break;
      case "chart-bar-hollow-factor":
        HFBarChart.filterAll();
        break;
      case "chart-bar-quality-factor":
        QFBarChart.filterAll();
        break;
      default:
        //Statements executed when none of the values match the value of the expression
        break;
    }

    redrawAll();
  }

buildBarChart(chart, dim, group, metric, x, y){
    //dc.barChart("#period-chart")
    chart
      .width(300)
      .height(180)
      .dimension(dim)
      .group(group)
      .x(d3.scale.linear().domain([0, 5.2]))
      .elasticY(true)
      .centerBar(true)
      .barPadding(5)
      .xAxisLabel(x)
      .yAxisLabel(y)
    return chart;
  }

  buildBubbleChart(chart, dim, group, x, y){
        //console.log(group.top(2));
      chart
        .width(400)
        .height(250)
        .transitionDuration(1500)
        .margins({top:10, right:50, bottom:30, left:40})
        .dimension(dim)
        .group(group)
        .ordinalColors(colorbrewer.Spectral[7])
        .colorAccessor((p) => {
          return p.key;
        })
        .keyAccessor((p) => {
          //return p.value.quality.avg;
          return p.value[x].avg;
        })
        .valueAccessor((p) => {
          return p.value[y].avg;
        })
        .radiusValueAccessor((p) => {
          return p.value.fun.count;
        })
        .maxBubbleRelativeSize(0.2)
        .x(d3.scale.linear().domain([0, 5]))
        .y(d3.scale.linear().domain([0, 5]))
        .r(d3.scale.linear().domain([0, 100]))
        .elasticY(false)
        .elasticX(false)
        .yAxisPadding(100)
        .xAxisPadding(500)
        .renderHorizontalGridLines(true)
        .renderVerticalGridLines(true)
        .xAxisLabel(x)
        .yAxisLabel(y)
        .yAxis().tickFormat(function (v) {
          return v + '%';
        });
    return chart;
  }

  formatData(data){

    const surfData = data;

    const fullDateFormat = d3.time.format("%a, %d %b %Y %X %Z");
    const yearFormat = d3.time.format('%Y');
    const monthFormat = d3.time.format('%b');
    const dayFormat = d3.time.format('%a');

    surfData.forEach(d=>{
      let dateObj  = new Date(d.sessionDate);
      d.sessionDateFormatted = fullDateFormat(dateObj);
      d.sessionYear = +yearFormat(dateObj);
      d.sessionMonth = monthFormat(dateObj);
      d.sessionDay = dayFormat(dateObj);
    });

    return surfData;
  }

  buildXDimensions(ttx){
    // create dimensions (x-axis values)
    const qualityFactorDim  = ttx.dimension(dc.pluck("waveQuality"));
    const hollowFactorDim  = ttx.dimension(dc.pluck("hollowness"));
    const crowdFactorDim  = ttx.dimension(dc.pluck("crowdedness"));
    const funFactorDim  = ttx.dimension(pluck("funFactor"));
    const yearDim  = ttx.dimension(pluck("sessionYear"));
    const monthDim  = ttx.dimension(pluck("sessionMonth"));
    const dayDim  = ttx.dimension(pluck("sessionDay"));
    const stickDimQuality  = ttx.dimension(pluck("board", (x,i) => {
      return x.name;
    }));
    const stickDimCrowd  = ttx.dimension(pluck("board", (x,i) => {
      return x.name;
    }));
    const stickDimHollow  = ttx.dimension(pluck("board", (x,i) => {
      return x.name;
    }));

    const xDims = { qualityFactorDim, hollowFactorDim, crowdFactorDim,
                    funFactorDim, yearDim, monthDim, dayDim,
                    stickDimQuality, stickDimCrowd, stickDimHollow };
    return xDims;

  }

  buildYGroups(ttx, xDims){

    const {qualityFactorDim, hollowFactorDim, crowdFactorDim,
           funFactorDim, yearDim, monthDim, dayDim,
           stickDimQuality, stickDimCrowd, stickDimHollow} = xDims;

    // create groups (y-axis values)
    const all = ttx.groupAll();
    const countPerQualityFactor = qualityFactorDim.group().reduceCount();
    const countPerHollowFactor = hollowFactorDim.group().reduceCount();
    const countPerCrowdFactor = crowdFactorDim.group().reduceCount();
    const countPerFunFactor = funFactorDim.group().reduceCount();
    const countPerYear = yearDim.group().reduceCount();
    const countPerMonth = monthDim.group().reduceCount();
    const countPerDay = dayDim.group().reduceCount();
    //map reduce functions
    let stickGroup = stickDimQuality.group();
    let bReducer = reductio();
    bReducer.value("quality").count(true).sum((d)=>{return d.waveQuality;}).avg(true);
    bReducer.value("fun").count(true).sum((d)=>{return d.funFactor}).avg(true);
    bReducer.value("crowd").count(true).sum((d)=>{return d.crowdedness}).avg(true);
    bReducer.value("hollow").count(true).sum((d)=>{return d.hollowness}).avg(true);
    bReducer(stickGroup);

    const yGroups = {all, countPerQualityFactor, countPerHollowFactor, countPerCrowdFactor,
                     countPerFunFactor, countPerYear, countPerMonth, countPerDay,
                     stickGroup};

    return yGroups;

  }

  //end of class
}
<|endoftext|>