Author: humbedooh Date: Sun Aug 26 14:42:11 2018 New Revision: 1839221 URL: http://svn.apache.org/viewvc?rev=1839221&view=rev Log: Initial checkout of site and generator Added: comdev/project-logos/site/ comdev/project-logos/site/css/ comdev/project-logos/site/css/logofinder.css comdev/project-logos/site/images/ comdev/project-logos/site/images/eps.png (with props) comdev/project-logos/site/images/pdf.png (with props) comdev/project-logos/site/images/png.png (with props) comdev/project-logos/site/index.html comdev/project-logos/site/js/ comdev/project-logos/site/js/base.js comdev/project-logos/site/js/http.js comdev/project-logos/site/js/logofinder.js comdev/project-logos/site/js/scaffolding.js comdev/project-logos/site/tools/ comdev/project-logos/site/tools/compile.py comdev/project-logos/tools/ comdev/project-logos/tools/compile.py Added: comdev/project-logos/site/css/logofinder.css URL: http://svn.apache.org/viewvc/comdev/project-logos/site/css/logofinder.css?rev=1839221&view=auto ============================================================================== --- comdev/project-logos/site/css/logofinder.css (added) +++ comdev/project-logos/site/css/logofinder.css Sun Aug 26 14:42:11 2018 @@ -0,0 +1,81 @@ +body { + background-color: #EEE; + color: #222; + line-height: 1.25 !important; +} + +.project_rect { + color: #000; + width: 400px; + height: 340px; + text-align: center; + font-family: sans-serif; + border: 1.5px solid #3338; + border-radius: 5px; + background-color: #FFF; + display: inline-block; + margin: 10px; + font-size: 12px; + position: relative; + overflow: hidden; +} + +#intro { + margin: 10px auto; + color: #000; + width: 1000px; + height: 80px; + text-align: center; + font-family: sans-serif; + font-size: 12px; + border: 1.5px solid #3338; + border-radius: 5px; + background-color: #FFFC; + padding: 4px; + position: relative; + overflow: hidden; +} + +.project_logo { + width: 400px; + height: 160px; + position: relative; + vertical-align: middle; + line-height: 180px; + text-align: center; +} + +.project_rect > p { + font-size: 11px; + padding: 2px; +} + +form { + font-family: sans-serif; + font-size: 16px; + text-align: center; +} + +h3 { + text-align: center; + font-family: sans-serif; + color: #333; +} + +.img_download { + border: 1px solid #3332; + margin: 2px; + padding: 2px; + font-size: 10px; + font-family: sans-serif; + display: inline-block; + overflow: hidden; + width: 105px; + line-height: 1.1; + height: 50px; + text-align: center; +} + +.img_download:hover { + background: #FFC; +} \ No newline at end of file Added: comdev/project-logos/site/images/eps.png URL: http://svn.apache.org/viewvc/comdev/project-logos/site/images/eps.png?rev=1839221&view=auto ============================================================================== Binary file - no diff available. Propchange: comdev/project-logos/site/images/eps.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: comdev/project-logos/site/images/pdf.png URL: http://svn.apache.org/viewvc/comdev/project-logos/site/images/pdf.png?rev=1839221&view=auto ============================================================================== Binary file - no diff available. Propchange: comdev/project-logos/site/images/pdf.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: comdev/project-logos/site/images/png.png URL: http://svn.apache.org/viewvc/comdev/project-logos/site/images/png.png?rev=1839221&view=auto ============================================================================== Binary file - no diff available. Propchange: comdev/project-logos/site/images/png.png ------------------------------------------------------------------------------ svn:mime-type = application/octet-stream Added: comdev/project-logos/site/index.html URL: http://svn.apache.org/viewvc/comdev/project-logos/site/index.html?rev=1839221&view=auto ============================================================================== --- comdev/project-logos/site/index.html (added) +++ comdev/project-logos/site/index.html Sun Aug 26 14:42:11 2018 @@ -0,0 +1,133 @@ + + + + + + Apache Project logos + + + + + + + + + + + + + + + + + + + + + + Welcome to The Apache Software Foundation! + + + + + + + + + +
+ +
+ + + +
+

Apache Project Logos

+ Find a project: +   + +
+
+ How do I get my project logo on this page?
+ Commit your original logo (svg, eps, ai, pdf accepted) to + this location, and call it $project.$ext, for instance couchdb.svg. + If you have multiple versions to display (for instance a vertical and horizontal version), you can call them $project-1.ext, $project-2.ext and so on, + and the site will pick up on that. + You can also send it or a query to dev@community.apache.org if you need further assistance. + This site is automatically regenerated every hour. +
+
+ +
+ + + + + + + + + + Added: comdev/project-logos/site/js/base.js URL: http://svn.apache.org/viewvc/comdev/project-logos/site/js/base.js?rev=1839221&view=auto ============================================================================== --- comdev/project-logos/site/js/base.js (added) +++ comdev/project-logos/site/js/base.js Sun Aug 26 14:42:11 2018 @@ -0,0 +1,139 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/** + * String formatting prototype + * A'la printf + */ + +String.prototype.format = function() { + let args = arguments; + let n = 0; + let t = this; + let rtn = this.replace(/(?!%)?%([-+]*)([0-9.]*)([a-zA-Z])/g, function(m, pm, len, fmt) { + len = parseInt(len || '1'); + // We need the correct number of args, balk otherwise, using ourselves to format the error! + if (args.length <= n) { + let err = "Error interpolating string '%s': Expected at least %u argments, only got %u!".format(t, n+1, args.length); + console.log(err); + throw err; + } + let varg = args[n]; + n++; + switch (fmt) { + case 's': + if (typeof(varg) == 'function') { + varg = '(function)'; + } + return varg; + // For now, let u, d and i do the same thing + case 'd': + case 'i': + case 'u': + varg = parseInt(varg).pad(len); // truncate to Integer, pad if needed + return varg; + } + }); + return rtn; +} + + +/** + * Number prettification prototype: + * Converts 1234567 into 1,234,567 etc + */ + +Number.prototype.pretty = function(fix) { + if (fix) { + return String(this.toFixed(fix)).replace(/(\d)(?=(\d{3})+\.)/g, '$1,'); + } + return String(this.toFixed(0)).replace(/(\d)(?=(\d{3})+$)/g, '$1,'); +}; + + +/** + * Number padding + * usage: 123.pad(6) -> 000123 + */ + +Number.prototype.pad = function(n) { + var str; + str = String(this); + + /* Do we need to pad? if so, do it using String.repeat */ + if (str.length < n) { + str = "0".repeat(n - str.length) + str; + } + return str; +}; + + +/* Func for converting a date to YYYY-MM-DD HH:MM */ + +Date.prototype.ISOBare = function() { + var M, d, h, m, y; + y = this.getFullYear(); + m = (this.getMonth() + 1).pad(2); + d = this.getDate().pad(2); + h = this.getHours().pad(2); + M = this.getMinutes().pad(2); + return y + "-" + m + "-" + d + " " + h + ":" + M; +}; + + +/* isArray: function to detect if an object is an array */ + +isArray = function(value) { + return value && typeof value === 'object' && value instanceof Array && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length')); +}; + + +/* isHash: function to detect if an object is a hash */ + +isHash = function(value) { + return value && typeof value === 'object' && !isArray(value); +}; + + +/* Remove an array element by value */ + +Array.prototype.remove = function(val) { + var i, item, j, len; + for (i = j = 0, len = this.length; j < len; i = ++j) { + item = this[i]; + if (item === val) { + this.splice(i, 1); + return this; + } + } + return this; +}; + + +/* Check if array has value */ +Array.prototype.has = function(val) { + var i, item, j, len; + for (i = j = 0, len = this.length; j < len; i = ++j) { + item = this[i]; + if (item === val) { + return true; + } + } + return false; +}; + + Added: comdev/project-logos/site/js/http.js URL: http://svn.apache.org/viewvc/comdev/project-logos/site/js/http.js?rev=1839221&view=auto ============================================================================== --- comdev/project-logos/site/js/http.js (added) +++ comdev/project-logos/site/js/http.js Sun Aug 26 14:42:11 2018 @@ -0,0 +1,762 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +/** + * String formatting prototype + * A'la printf + */ + +String.prototype.format = function() { + let args = arguments; + let n = 0; + let t = this; + let rtn = this.replace(/(?!%)?%([-+]*)([0-9.]*)([a-zA-Z])/g, function(m, pm, len, fmt) { + len = parseInt(len || '1'); + // We need the correct number of args, balk otherwise, using ourselves to format the error! + if (args.length <= n) { + let err = "Error interpolating string '%s': Expected at least %u argments, only got %u!".format(t, n+1, args.length); + console.log(err); + throw err; + } + let varg = args[n]; + n++; + switch (fmt) { + case 's': + if (typeof(varg) == 'function') { + varg = '(function)'; + } + return varg; + // For now, let u, d and i do the same thing + case 'd': + case 'i': + case 'u': + varg = parseInt(varg).pad(len); // truncate to Integer, pad if needed + return varg; + } + }); + return rtn; +} + + +/** + * Number prettification prototype: + * Converts 1234567 into 1,234,567 etc + */ + +Number.prototype.pretty = function(fix) { + if (fix) { + return String(this.toFixed(fix)).replace(/(\d)(?=(\d{3})+\.)/g, '$1,'); + } + return String(this.toFixed(0)).replace(/(\d)(?=(\d{3})+$)/g, '$1,'); +}; + + +/** + * Number padding + * usage: 123.pad(6) -> 000123 + */ + +Number.prototype.pad = function(n) { + var str; + str = String(this); + + /* Do we need to pad? if so, do it using String.repeat */ + if (str.length < n) { + str = "0".repeat(n - str.length) + str; + } + return str; +}; + + +/* Func for converting a date to YYYY-MM-DD HH:MM */ + +Date.prototype.ISOBare = function() { + var M, d, h, m, y; + y = this.getFullYear(); + m = (this.getMonth() + 1).pad(2); + d = this.getDate().pad(2); + h = this.getHours().pad(2); + M = this.getMinutes().pad(2); + return y + "-" + m + "-" + d + " " + h + ":" + M; +}; + + +/* isArray: function to detect if an object is an array */ + +isArray = function(value) { + return value && typeof value === 'object' && value instanceof Array && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length')); +}; + + +/* isHash: function to detect if an object is a hash */ + +isHash = function(value) { + return value && typeof value === 'object' && !isArray(value); +}; + + +/* Remove an array element by value */ + +Array.prototype.remove = function(val) { + var i, item, j, len; + for (i = j = 0, len = this.length; j < len; i = ++j) { + item = this[i]; + if (item === val) { + this.splice(i, 1); + return this; + } + } + return this; +}; + + +/* Check if array has value */ +Array.prototype.has = function(val) { + var i, item, j, len; + for (i = j = 0, len = this.length; j < len; i = ++j) { + item = this[i]; + if (item === val) { + return true; + } + } + return false; +}; + + + + +// URL calls currently 'in escrow'. This controls the spinny wheel animation +var async_escrow = {} +var async_maxwait = 250; // ms to wait before displaying spinner +var async_status = 'clear'; +var async_cache = {} + +// Escrow spinner check +async function escrow_check() { + let now = new Date(); + let show_spinner = false; + for (var k in async_escrow) { + if ( (now - async_escrow[k]) > async_maxwait ) { + show_spinner = true; + break; + } + } + // Fetch or create the spinner + let spinner = document.getElementById('spinner'); + if (!spinner) { + spinner = new HTML('div', { id: 'spinner', class: 'spinner'}); + spinwheel = new HTML('div', {id: 'spinwheel', class: 'spinwheel'}); + spinner.inject(spinwheel); + spinner.inject(new HTML('h2', {}, "Loading, please wait..")); + document.body.appendChild(spinner); + } + // Show or don't show spinner? + if (show_spinner) { + spinner.style.display = 'block'; + if (async_status === 'clear') { + console.log("Waiting for JSON resource, deploying spinner"); + async_status = 'waiting'; + } + } else { + spinner.style.display = 'none'; + if (async_status === 'waiting') { + console.log("All URLs out of escrow, dropping spinner"); + async_status = 'clear'; + } + } +} + +async function async_snap(error) { + msg = await error.text(); + msg = (msg||"An unknown error occured, possibly an internal browser issue").replace(/<.*?>/g, ""); // strip HTML tags + modal("An error occured", "An error code %u occured while trying to fetch %s:\n%s".format(error.status, error.url, msg), "error"); +} + + +// Asynchronous GET call +async function GET(url, callback, state, snap, method, body) { + method = method || 'get' + console.log("Fetching JSON resource at %s".format(url)) + let pkey = "GET-%s-%s".format(callback, url); + let res = undefined; + let res_json = undefined; + state = state || {}; + state.url = url; + if (state && state.cached === true && async_cache[url]) { + console.log("Fetching %s from cache".format(url)); + res_json = async_cache[url]; + } + else { + try { + let meta = {method: method, credentials: 'include', referrerPolicy: 'unsafe-url', headers: {'x-original-referral': document.referrer}}; + if (body) { + meta.body = body; + } + console.log("putting %s in escrow...".format(url)); + async_escrow[pkey] = new Date(); // Log start of request in escrow dict + const rv = await fetch(url, meta); // Wait for resource... + + // Since this is an async request, the request may have been canceled + // by the time we get a response. Only do callback if not. + if (async_escrow[pkey] !== undefined) { + delete async_escrow[pkey]; // move out of escrow when fetched + res = rv; + } + } + catch (e) { + delete async_escrow[pkey]; // move out of escrow if failed + console.log("The URL %s could not be fetched: %s".format(url, e)); + if (snap) snap({}, {reason: e}); + else { + modal("An error occured", "An error occured while trying to fetch %s:\n%s".format(url, e), "error"); + } + } + } + if (res !== undefined || res_json !== undefined) { + // We expect a 2xx return code (usually 200 or 201), snap otherwise + if ((res_json) || (res.status >= 200 && res.status < 300)) { + console.log("Successfully fetched %s".format(url)) + if (res_json) { + js = res_json; + } else { + js = await res.json(); + async_cache[url] = js; + } + if (callback) { + callback(state, js); + } else { + console.log("No callback function was registered for %s, ignoring result.".format(url)); + } + } else { + console.log("URL %s returned HTTP code %u, snapping!".format(url, res.status)); + try { + js = await res.json(); + snap(state, js); + return; + } catch (e) {} + if (snap) snap(res); + else async_snap(res); + } + } +} + + +// DELETE wrapper +async function DELETE(url, callback, state, snap) { + return GET(url, callback, state, snap, 'delete'); +} + +// POST wrapper +async function POST(url, callback, state, snap, json) { + return GET(url, callback, state, snap, 'post', JSON.stringify(json)); +} + +// PUT wrapper +async function PUT(url, callback, state, snap, json) { + return GET(url, callback, state, snap, 'put', JSON.stringify(json)); +} + +// PATCH wrapper +async function PATCH(url, callback, state, snap, json) { + return GET(url, callback, state, snap, 'PATCH', JSON.stringify(json)); +} + +// whatwg fetch for IE +(function(self) { + 'use strict'; + + if (self.fetch) { + return + } + + var support = { + searchParams: 'URLSearchParams' in self, + iterable: 'Symbol' in self && 'iterator' in Symbol, + blob: 'FileReader' in self && 'Blob' in self && (function() { + try { + new Blob() + return true + } catch(e) { + return false + } + })(), + formData: 'FormData' in self, + arrayBuffer: 'ArrayBuffer' in self + } + + if (support.arrayBuffer) { + var viewClasses = [ + '[object Int8Array]', + '[object Uint8Array]', + '[object Uint8ClampedArray]', + '[object Int16Array]', + '[object Uint16Array]', + '[object Int32Array]', + '[object Uint32Array]', + '[object Float32Array]', + '[object Float64Array]' + ] + + var isDataView = function(obj) { + return obj && DataView.prototype.isPrototypeOf(obj) + } + + var isArrayBufferView = ArrayBuffer.isView || function(obj) { + return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1 + } + } + + function normalizeName(name) { + if (typeof name !== 'string') { + name = String(name) + } + if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { + throw new TypeError('Invalid character in header field name') + } + return name.toLowerCase() + } + + function normalizeValue(value) { + if (typeof value !== 'string') { + value = String(value) + } + return value + } + + // Build a destructive iterator for the value list + function iteratorFor(items) { + var iterator = { + next: function() { + var value = items.shift() + return {done: value === undefined, value: value} + } + } + + if (support.iterable) { + iterator[Symbol.iterator] = function() { + return iterator + } + } + + return iterator + } + + function Headers(headers) { + this.map = {} + + if (headers instanceof Headers) { + headers.forEach(function(value, name) { + this.append(name, value) + }, this) + } else if (Array.isArray(headers)) { + headers.forEach(function(header) { + this.append(header[0], header[1]) + }, this) + } else if (headers) { + Object.getOwnPropertyNames(headers).forEach(function(name) { + this.append(name, headers[name]) + }, this) + } + } + + Headers.prototype.append = function(name, value) { + name = normalizeName(name) + value = normalizeValue(value) + var oldValue = this.map[name] + this.map[name] = oldValue ? oldValue+','+value : value + } + + Headers.prototype['delete'] = function(name) { + delete this.map[normalizeName(name)] + } + + Headers.prototype.get = function(name) { + name = normalizeName(name) + return this.has(name) ? this.map[name] : null + } + + Headers.prototype.has = function(name) { + return this.map.hasOwnProperty(normalizeName(name)) + } + + Headers.prototype.set = function(name, value) { + this.map[normalizeName(name)] = normalizeValue(value) + } + + Headers.prototype.forEach = function(callback, thisArg) { + for (var name in this.map) { + if (this.map.hasOwnProperty(name)) { + callback.call(thisArg, this.map[name], name, this) + } + } + } + + Headers.prototype.keys = function() { + var items = [] + this.forEach(function(value, name) { items.push(name) }) + return iteratorFor(items) + } + + Headers.prototype.values = function() { + var items = [] + this.forEach(function(value) { items.push(value) }) + return iteratorFor(items) + } + + Headers.prototype.entries = function() { + var items = [] + this.forEach(function(value, name) { items.push([name, value]) }) + return iteratorFor(items) + } + + if (support.iterable) { + Headers.prototype[Symbol.iterator] = Headers.prototype.entries + } + + function consumed(body) { + if (body.bodyUsed) { + return Promise.reject(new TypeError('Already read')) + } + body.bodyUsed = true + } + + function fileReaderReady(reader) { + return new Promise(function(resolve, reject) { + reader.onload = function() { + resolve(reader.result) + } + reader.onerror = function() { + reject(reader.error) + } + }) + } + + function readBlobAsArrayBuffer(blob) { + var reader = new FileReader() + var promise = fileReaderReady(reader) + reader.readAsArrayBuffer(blob) + return promise + } + + function readBlobAsText(blob) { + var reader = new FileReader() + var promise = fileReaderReady(reader) + reader.readAsText(blob) + return promise + } + + function readArrayBufferAsText(buf) { + var view = new Uint8Array(buf) + var chars = new Array(view.length) + + for (var i = 0; i < view.length; i++) { + chars[i] = String.fromCharCode(view[i]) + } + return chars.join('') + } + + function bufferClone(buf) { + if (buf.slice) { + return buf.slice(0) + } else { + var view = new Uint8Array(buf.byteLength) + view.set(new Uint8Array(buf)) + return view.buffer + } + } + + function Body() { + this.bodyUsed = false + + this._initBody = function(body) { + this._bodyInit = body + if (!body) { + this._bodyText = '' + } else if (typeof body === 'string') { + this._bodyText = body + } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { + this._bodyBlob = body + } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { + this._bodyFormData = body + } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { + this._bodyText = body.toString() + } else if (support.arrayBuffer && support.blob && isDataView(body)) { + this._bodyArrayBuffer = bufferClone(body.buffer) + // IE 10-11 can't handle a DataView body. + this._bodyInit = new Blob([this._bodyArrayBuffer]) + } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) { + this._bodyArrayBuffer = bufferClone(body) + } else { + throw new Error('unsupported BodyInit type') + } + + if (!this.headers.get('content-type')) { + if (typeof body === 'string') { + this.headers.set('content-type', 'text/plain;charset=UTF-8') + } else if (this._bodyBlob && this._bodyBlob.type) { + this.headers.set('content-type', this._bodyBlob.type) + } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) { + this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8') + } + } + } + + if (support.blob) { + this.blob = function() { + var rejected = consumed(this) + if (rejected) { + return rejected + } + + if (this._bodyBlob) { + return Promise.resolve(this._bodyBlob) + } else if (this._bodyArrayBuffer) { + return Promise.resolve(new Blob([this._bodyArrayBuffer])) + } else if (this._bodyFormData) { + throw new Error('could not read FormData body as blob') + } else { + return Promise.resolve(new Blob([this._bodyText])) + } + } + + this.arrayBuffer = function() { + if (this._bodyArrayBuffer) { + return consumed(this) || Promise.resolve(this._bodyArrayBuffer) + } else { + return this.blob().then(readBlobAsArrayBuffer) + } + } + } + + this.text = function() { + var rejected = consumed(this) + if (rejected) { + return rejected + } + + if (this._bodyBlob) { + return readBlobAsText(this._bodyBlob) + } else if (this._bodyArrayBuffer) { + return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer)) + } else if (this._bodyFormData) { + throw new Error('could not read FormData body as text') + } else { + return Promise.resolve(this._bodyText) + } + } + + if (support.formData) { + this.formData = function() { + return this.text().then(decode) + } + } + + this.json = function() { + return this.text().then(JSON.parse) + } + + return this + } + + // HTTP methods whose capitalization should be normalized + var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] + + function normalizeMethod(method) { + var upcased = method.toUpperCase() + return (methods.indexOf(upcased) > -1) ? upcased : method + } + + function Request(input, options) { + options = options || {} + var body = options.body + + if (input instanceof Request) { + if (input.bodyUsed) { + throw new TypeError('Already read') + } + this.url = input.url + this.credentials = input.credentials + if (!options.headers) { + this.headers = new Headers(input.headers) + } + this.method = input.method + this.mode = input.mode + if (!body && input._bodyInit != null) { + body = input._bodyInit + input.bodyUsed = true + } + } else { + this.url = String(input) + } + + this.credentials = options.credentials || this.credentials || 'omit' + if (options.headers || !this.headers) { + this.headers = new Headers(options.headers) + } + this.method = normalizeMethod(options.method || this.method || 'GET') + this.mode = options.mode || this.mode || null + this.referrer = null + + if ((this.method === 'GET' || this.method === 'HEAD') && body) { + throw new TypeError('Body not allowed for GET or HEAD requests') + } + this._initBody(body) + } + + Request.prototype.clone = function() { + return new Request(this, { body: this._bodyInit }) + } + + function decode(body) { + var form = new FormData() + body.trim().split('&').forEach(function(bytes) { + if (bytes) { + var split = bytes.split('=') + var name = split.shift().replace(/\+/g, ' ') + var value = split.join('=').replace(/\+/g, ' ') + form.append(decodeURIComponent(name), decodeURIComponent(value)) + } + }) + return form + } + + function parseHeaders(rawHeaders) { + var headers = new Headers() + // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space + // https://tools.ietf.org/html/rfc7230#section-3.2 + var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ') + preProcessedHeaders.split(/\r?\n/).forEach(function(line) { + var parts = line.split(':') + var key = parts.shift().trim() + if (key) { + var value = parts.join(':').trim() + headers.append(key, value) + } + }) + return headers + } + + Body.call(Request.prototype) + + function Response(bodyInit, options) { + if (!options) { + options = {} + } + + this.type = 'default' + this.status = options.status === undefined ? 200 : options.status + this.ok = this.status >= 200 && this.status < 300 + this.statusText = 'statusText' in options ? options.statusText : 'OK' + this.headers = new Headers(options.headers) + this.url = options.url || '' + this._initBody(bodyInit) + } + + Body.call(Response.prototype) + + Response.prototype.clone = function() { + return new Response(this._bodyInit, { + status: this.status, + statusText: this.statusText, + headers: new Headers(this.headers), + url: this.url + }) + } + + Response.error = function() { + var response = new Response(null, {status: 0, statusText: ''}) + response.type = 'error' + return response + } + + var redirectStatuses = [301, 302, 303, 307, 308] + + Response.redirect = function(url, status) { + if (redirectStatuses.indexOf(status) === -1) { + throw new RangeError('Invalid status code') + } + + return new Response(null, {status: status, headers: {location: url}}) + } + + self.Headers = Headers + self.Request = Request + self.Response = Response + + self.fetch = function(input, init) { + return new Promise(function(resolve, reject) { + var request = new Request(input, init) + var xhr = new XMLHttpRequest() + + xhr.onload = function() { + var options = { + status: xhr.status, + statusText: xhr.statusText, + headers: parseHeaders(xhr.getAllResponseHeaders() || '') + } + options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL') + var body = 'response' in xhr ? xhr.response : xhr.responseText + resolve(new Response(body, options)) + } + + xhr.onerror = function() { + reject(new TypeError('Network request failed')) + } + + xhr.ontimeout = function() { + reject(new TypeError('Network request failed')) + } + + xhr.open(request.method, request.url, true) + + if (request.credentials === 'include') { + xhr.withCredentials = true + } else if (request.credentials === 'omit') { + xhr.withCredentials = false + } + + if ('responseType' in xhr && support.blob) { + xhr.responseType = 'blob' + } + + request.headers.forEach(function(value, name) { + xhr.setRequestHeader(name, value) + }) + + xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) + }) + } + self.fetch.polyfill = true +})(typeof self !== 'undefined' ? self : this); Added: comdev/project-logos/site/js/logofinder.js URL: http://svn.apache.org/viewvc/comdev/project-logos/site/js/logofinder.js?rev=1839221&view=auto ============================================================================== --- comdev/project-logos/site/js/logofinder.js (added) +++ comdev/project-logos/site/js/logofinder.js Sun Aug 26 14:42:11 2018 @@ -0,0 +1,182 @@ +var pjson = {}; +var logoalts = {}; + +function change_logo(key, x) { + x = parseInt(x); + for (var i = 1; i < 10; i++) { + let obj = document.getElementById('logo_%s_%u'.format(key, i)); + if (obj) { + if (x == i) { + obj.style.display = 'block'; + let img = document.getElementById('default_%s'.format(key)); + ext = logoalts[key][x-1]; + if (ext == 'default') { + img.src = 'res/%s/default.png'.format(key, key, ext); + } + else { + img.src = 'res/%s/%s%s.png'.format(key, key, ext); + } + + } else { + obj.style.display = 'none'; + } + } + } + +} + +function make_div(key, project) { + let div = new HTML('div', { class: 'project_rect'}); + let pname = 'Apache %s'.format(project.name); + if (project.podling) { + pname += " (incubating)"; + } + let title = new HTML('h4', pname); + let idiv = new HTML('div', {class: 'project_logo'}); + let img = new HTML('img', {id: 'default_%s'.format(key), src: 'res/%s/default.png'.format(key), style: {maxWidth: '320px', maxHeight: '160px'}}); + if (project.has_default) { + + } else { + img = new HTML('img', {src: 'res/%s'.format(project.images[0].filename), style: {maxWidth: '260px', maxHeight: '160px'}}); + } + div.inject(title); + idiv.inject(img); + div.inject(idiv); + + if (project.description && project.description.length > 0) { + pd = project.description; + if (pd.length > 150) { pd = pd.substring(0,150) + "..."} + div.inject(new HTML('p', [ + pd + ' - ', + new HTML('a', {href: project.website}, project.website) + ])); + + + } + + originals = {}; + links = new HTML('p', {style: {textAlign: 'left'}}); + let il = {}; + for (var i in project.images) { + let img = project.images[i]; + if (img.format) { + if (il[img.filename]) continue; + il[img.filename] = true; + originals[img.original] = originals[img.original] || []; + originals[img.original].push(img); + } + } + let x = 0; + logoalts[key] = []; + let originals_sorted = []; + for (var k in originals) originals_sorted.push(k); + originals_sorted.sort(); + let sel = new HTML('select', {onchange: 'change_logo("%s", this.value)'.format(key)}); + div.inject(sel); + for (var z = 0; z < originals_sorted.length; z++) { + let original = originals_sorted[z]; + x++; + let ext = 'default'; + let m = original.match(/(-\S+)$/); + if (m) { ext = m[1]; } + logoalts[key].push(ext); + let odiv = new HTML('div', {id: 'logo_%s_%u'.format(key, x)}); + let opt = new HTML('option', { value: '%u'.format(x)}, "Version %u".format(x)); + sel.inject(opt); + let imgs = originals[original]; + for (var i = 0; i < imgs.length; i++) { + let img = imgs[i]; + let arr = [ + new HTML('img', {src:'images/%s.png'.format(img.format), style: {maxWidth: '24px', maxHeight: '24px'}}), + new HTML('br'), + ]; + let ltxt = "PNG raster"; + if (img.format == 'pdf') { + ltxt = "PDF document"; + } + arr.push(ltxt); + if (img.width && img.height) { + arr.push(new HTML('br')); + arr.push("(%s x %s pixels)".format(img.width, img.height)); + } + + let link = new HTML('a', {href: 'res/' + img.filename}, + new HTML('div', {class: 'img_download'}, + arr + ) + ); + odiv.inject(link); + } + if (x > 1) { + odiv.style.display = "none"; + } + div.inject(odiv); + } + if (x == 1) { + sel.style.display = "none"; + } + + return div; +} + +function find_project(name) { + name = name.toLowerCase(); + let wrapper = document.getElementById('wrapper'); + let obj = new HTML('div'); + wrapper.innerHTML = ""; + let num = 0; + let keys = []; + for (var key in pjson) { keys.push(key); } + keys.sort(); + for (var i = 0; i < keys.length; i++) { + let key = keys[i]; + let project = pjson[key]; + if (!project) continue; + if (project.name.toLowerCase().match(name) || key.toLowerCase().match(name)) { + if (project.has_default || project.images.length > 0) { + num++; + let div = make_div(key, project); + obj.inject(div); + } + } + } + let res = new HTML('h3', "Found %u projects".format(num)); + wrapper.inject(res); + wrapper.inject(obj); + location.hash = name; +} + +function render_projects(state, json) { + pjson = json; + let hash = location.hash.substr(1); + if (hash && hash.length > 0) { + document.getElementById('pkey').value = hash; + find_project(hash); + return; + } + let wrapper = document.getElementById('wrapper'); + let obj = new HTML('div'); + wrapper.innerHTML = ""; + let keys = []; + let num = 0; + for (var key in json) { keys.push(key); } + keys.sort(); + for (var i = 0; i < keys.length; i++) { + let key = keys[i]; + project = json[key]; + if (!project) continue; + if (project.has_default || project.images.length > 0) { + num++; + let div = make_div(key, project); + obj.inject(div); + } + } + let res = new HTML('h3', "Found %u projects".format(num)); + wrapper.inject(res); + wrapper.inject(obj); +} + +function init_projects() { + GET('res/logos.json?' + Math.random(), render_projects); +} + Added: comdev/project-logos/site/js/scaffolding.js URL: http://svn.apache.org/viewvc/comdev/project-logos/site/js/scaffolding.js?rev=1839221&view=auto ============================================================================== --- comdev/project-logos/site/js/scaffolding.js (added) +++ comdev/project-logos/site/js/scaffolding.js Sun Aug 26 14:42:11 2018 @@ -0,0 +1,191 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + + +/** + * HTML: DOM creator class + * args: + * - type: HTML element type (div, table, p etc) to produce + * - params: hash of element params to add (class, style etc) + * - children: optional child or children objects to insert into the new element + * Example: + * div = new HTML('div', { + * class: "footer", + * style: { + * fontWeight: "bold" + * } +#}, "Some text inside a div") + */ + +var txt = (msg) => document.createTextNode(msg); + +var HTML = (function() { + function HTML(type, params, children) { + + /* create the raw element, or clone if passed an existing element */ + var child, j, len, val; + if (typeof type === 'object') { + this.element = type.cloneNode(); + } else { + this.element = document.createElement(type); + } + + /* If params have been passed, set them */ + if (isHash(params)) { + for (var key in params) { + val = params[key]; + + /* Standard string value? */ + if (typeof val === "string" || typeof val === 'number') { + this.element.setAttribute(key, val); + } else if (isArray(val)) { + + /* Are we passing a list of data to set? concatenate then */ + this.element.setAttribute(key, val.join(" ")); + } else if (isHash(val)) { + + /* Are we trying to set multiple sub elements, like a style? */ + for (var subkey in val) { + let subval = val[subkey]; + if (!this.element[key]) { + throw "No such attribute, " + key + "!"; + } + this.element[key][subkey] = subval; + } + } + } + } else { + if (!children) { children = params } // shortcut! + } + + /* If any children have been passed, add them to the element */ + if (children) { + + /* If string, convert to textNode using txt() */ + if (typeof children === "string") { + this.element.inject(txt(children)); + } else { + + /* If children is an array of elems, iterate and add */ + if (isArray(children)) { + for (j = 0, len = children.length; j < len; j++) { + child = children[j]; + + /* String? Convert via txt() then */ + if (typeof child === "string") { + this.element.inject(txt(child)); + } else { + + /* Plain element, add normally */ + this.element.inject(child); + } + } + } else { + + /* Just a single element, add it */ + this.element.inject(children); + } + } + } + return this.element; + } + + return HTML; + +})(); + +/** + * prototype injector for HTML elements: + * Example: mydiv.inject(otherdiv) + */ + +HTMLElement.prototype.inject = function(child) { + var item, j, len; + if (isArray(child)) { + for (j = 0, len = child.length; j < len; j++) { + item = child[j]; + if (typeof item === 'string') { + item = txt(item); + } + this.appendChild(item); + } + } else { + if (typeof child === 'string') { + child = txt(child); + } + this.appendChild(child); + } + return child; +}; + + + +/** + * prototype for emptying an html element + */ + +HTMLElement.prototype.empty = function() { + var ndiv; + ndiv = this.cloneNode(); + this.parentNode.replaceChild(ndiv, this); + return ndiv; +}; + +function toggleView(id) { + let obj = document.getElementById(id); + if (obj) { + obj.style.display = (obj.style.display == 'block') ? 'none' : 'block'; + } +} + +function br() { + return new HTML('br'); +} + +// construction shortcuts for various elements +let _a = (a,b) => new HTML('a', a,b); +let _b = (a,b) => new HTML('b', a,b); +let _p = (a,b) => new HTML('p', a,b); +let _i = (a,b) => new HTML('i', a, b); +let _div = (a,b) => new HTML('div', a, b); +let _input = (a,b) => new HTML('input', a, b); +let _select = (a,b) => new HTML('select', a, b); +let _option = (a,b) => new HTML('option', a, b); +let _h1 = (a,b) => new HTML('h1', a, b); +let _h2 = (a,b) => new HTML('h2', a, b); +let _h3 = (a,b) => new HTML('h3', a, b); +let _h4 = (a,b) => new HTML('h4', a, b); +let _h5 = (a,b) => new HTML('h5', a, b); +let _kbd = (a,b) => new HTML('kbd', a, b); +let _pre = (a,b) => new HTML('pre', a, b); +let _hr = (a,b) => new HTML('hr', a, b); +let _span = (a,b) => new HTML('span', a, b); +let _textarea = (a,b) => new HTML('textarea', a, b); +let _get = (a) => document.getElementById(a); + + +function billitem(a,b,c, total) { + let d = _div({style: {position: 'relative', display: 'block'}}); + if (total) { d.style.fontWeight = 'bold'; d.style.borderTop = '2px solid #444'; } + let da = _div({style: {position: 'relative', width: '600px', display: 'inline-block'}}, a); + let db = _div({style: {position: 'relative', width: '60px', display: 'inline-block'}}, b); + let dc = _div({style: {position: 'relative', width: '80px', textAlign: 'right', display: 'inline-block'}}, c); + d.inject(da); + d.inject(db); + d.inject(dc); + return d; +} Added: comdev/project-logos/site/tools/compile.py URL: http://svn.apache.org/viewvc/comdev/project-logos/site/tools/compile.py?rev=1839221&view=auto ============================================================================== --- comdev/project-logos/site/tools/compile.py (added) +++ comdev/project-logos/site/tools/compile.py Sun Aug 26 14:42:11 2018 @@ -0,0 +1,207 @@ +#!/usr/bin/env python3 + +import os +import sys +import subprocess +import json +import requests +import re +from PIL import Image +import time + +# Standard in/out dirs +img_dir = '/svn/asf-logos' +out_dir = '/svn/logofinder/res' + +if len(sys.argv) > 2: + img_dir = sys.argv[1] + out_dir = sys.argv[2] + + +# svn up before processing +subprocess.check_output(('/usr/bin/svn', 'up', img_dir)) + +# Gather all images to process +files = [x for x in os.listdir(img_dir) if os.path.isfile(os.path.join(img_dir, x))] + +# Get all projects, committees, podlings +cmts = requests.get('https://whimsy.apache.org/public/committee-info.json').json() +pods = requests.get('https://whimsy.apache.org/public/public_podlings.json').json() +projs = requests.get('https://projects.apache.org/json/foundation/projects.json').json() + + +# Churn out a big json blob of projects +projects = {} +for k, cmt in cmts['committees'].items(): + k = k.replace('-', '') + if k == 'httpcomponents': + k = 'hc' + el = { + 'name': cmt['display_name'], + 'established': cmt['established'], + 'description': cmt['description'], + 'website': cmt['site'], + 'podling': False, + 'has_default': False, + 'images': [] + } + projects[k] = el + +for k, cmt in pods['podling'].items(): + k = k.replace('-', '') + el = { + 'name': cmt['name'], + 'established': cmt['startdate'], + 'description': cmt['description'], + 'website': "https://%s.apache.org/" % k, + 'podling': True, + 'has_default': False, + 'images': [] + } + if cmt['status'] == "current" and k not in projects: + projects[k] = el + +for k, cmt in projs.items(): + k = k.replace('-', '') + el = { + 'name': cmt['name'].replace('Apache ', ''), + 'established': cmt.get('created', 'Sub project of %s' % cmt['pmc']), + 'description': cmt.get('description', 'No description available'), + 'website': cmt.get('homepage', 'https://www.apache.org/'), + 'podling': False, + 'has_default': False, + 'images': [] + } + if k not in projects: + k = re.sub(r"_.+", "", k) + projects[k] = el + + +# Add foundation as a project +projects['foundation'] = { + 'name': 'Software Foundation', + 'established': '1999-03', + 'description': 'Foundation logo', + 'website': "https://www.apache.org/", + 'podling': False, + 'has_default': False, + 'images': [] +} + +# Prep montage for execution later +montage = ['/usr/bin/montage', '-geometry', '200x150+4+4', '-tile', '20x'] +montage_tlps = ['/usr/bin/montage', '-geometry', '200x150+4+4', '-tile', '20x'] +montage_large = ['/usr/bin/montage', '-geometry', '1200x600+20+20', '-tile', '8x'] +montage_wide = ['/usr/bin/montage', '-geometry', '1200x600+20+20', '-tile', '15x'] + + +# Process each file... +for file in files: + m = re.match(r"^([^.-]+).*?\.(.+)$", file) + project = m.group(1) + if project not in projects: + for k in projects: + if k.endswith("-%s" % project): + project = k + break + ext = m.group(2) + oext = ext + fpath = '%s/%s' % (img_dir, file) + st = os.stat(fpath) + skipit = False + if st.st_mtime < (time.time() - 4200) and os.path.exists('%s/%s/default.png' % (out_dir, project)): + print("Skipping %s" % fpath) + skipit = True + # EPS should be converted to PDF first, or inkscape borks :/ + if ext == 'eps': + xfile = file.replace('.'+ext, '') + if not skipit and not os.path.exists('%s/%s.pdf' % (img_dir, xfile)): + subprocess.check_output(('ps2pdf', '-dPDFSETTINGS=/prepress', '-dEPSCrop', '%s/%s' % (img_dir, file), '%s/pdftmp/%s.pdf' % (img_dir, xfile))) + ext = 'pdf' + file = 'pdftmp/' + xfile + '.pdf' + # Scalable formats + if ext in ['svg', 'ai', 'pdf', 'png']: + print("Converting %s to PNG/PDF" % file) + xfile = file.replace('.'+ext, '').replace('pdftmp/', '') + ppath = "%s/%s" % (out_dir, project) + if not os.path.isdir(ppath): + os.mkdir(ppath) + try: + if xfile == project or xfile == '%s-1' % project: + if not skipit: + subprocess.check_output(('inkscape', '-z', '%s/%s' % (img_dir, file), '-e', '%s/%s/default.png' % (out_dir, project), '-w', '720')) + projects[project]['has_default'] = True + except: + pass + + # PNG, normal res + if xfile == project or xfile == '%s-1' % project: + if project != 'foundation': + montage_large.append('%s/%s/%s.png' % (out_dir, project, xfile)) + montage_wide.append('%s/%s/%s.png' % (out_dir, project, xfile)) + try: + if not skipit: + subprocess.check_output(('inkscape', '-z', '%s/%s' % (img_dir, file), '-e', '%s/%s/%s.png' % (out_dir, project, xfile), '-w', '1200')) + im = Image.open('%s/%s/%s.png' % (out_dir, project, xfile)) + w = im.width + h = im.height + projects[project]['images'].append({'original': xfile, 'name': '%s' % xfile, 'filename': '%s/%s.png' % (project, xfile), 'format': 'png', 'width': w, 'height': h}) + except: + pass + # PNG, high res + try: + if not skipit: + subprocess.check_output(('inkscape', '-z', '%s/%s' % (img_dir, file), '-e', '%s/%s/%s_highres.png' % (out_dir, project, xfile), '-w', '3600')) + im = Image.open('%s/%s/%s_highres.png' % (out_dir, project, xfile)) + w = im.width + h = im.height + projects[project]['images'].append({'original': xfile, 'name': '%s (high res)' % xfile, 'filename': '%s/%s_highres.png' % (project, xfile), 'format': 'png', 'width': w, 'height': h}) + except: + pass + try: + if not skipit: + subprocess.check_output(('inkscape', '-z', '%s/%s' % (img_dir, file), '-A', '%s/%s/%s.pdf' % (out_dir, project, xfile), '-w', '1200')) + projects[project]['images'].append({'original': xfile, 'name': xfile, 'filename': '%s/%s.pdf' % (project, xfile), 'format': 'pdf'}) + except: + pass + +with open("%s/logos.json" % out_dir, "w") as f: + json.dump(projects, f, indent = 2) + + + +for project in projects: + xp = '%s/%s/default.png' % (out_dir, project) + if os.path.exists(xp): + if project != 'foundation': + montage.append(xp) + if not projects[project]['podling']: + montage_tlps.append(xp) + +montage.append('%s../montages/standard.png' % out_dir) +montage_tlps.append('%s../montages/standard_tlps_only.png' % out_dir) +montage_large.append('%s../montages/highres_tall.png' % out_dir) +montage_wide.append('%s../montages/highres_wide.png' % out_dir) + +try: + st = os.stat('%s../montages/standard.png' % out_dir) +except: + st = None +if (not st) or st.st_mtime < (time.time() - 43200): + print("Making montage...") + subprocess.check_output(montage) + subprocess.check_output(montage_tlps) + print("Making montage (high res, tall)...") + subprocess.check_output(montage_large) + print("Making montage (high res, wide)...") + subprocess.check_output(montage_wide) +else: + print("Skipping montages...") + +print("The following TLPs are currently not represented: ") +for k, cmt in cmts['committees'].items(): + k = k.replace('-', '') + if not projects.get(k): + continue + if len(projects[k]['images']) == 0: + print(k) Added: comdev/project-logos/tools/compile.py URL: http://svn.apache.org/viewvc/comdev/project-logos/tools/compile.py?rev=1839221&view=auto ============================================================================== --- comdev/project-logos/tools/compile.py (added) +++ comdev/project-logos/tools/compile.py Sun Aug 26 14:42:11 2018 @@ -0,0 +1,208 @@ +#!/usr/bin/env python3 + +import os +import sys +import subprocess +import json +import requests +import re +from PIL import Image +import time + +# Standard in/out dirs +img_dir = '/svn/project-logos/originals' +out_dir = '/var/www/html/logos/res' + +if len(sys.argv) > 2: + img_dir = sys.argv[1] + out_dir = sys.argv[2] + + +# svn up before processing +subprocess.check_output(('/usr/bin/svn', 'up', img_dir)) + +# Gather all images to process +files = [x for x in os.listdir(img_dir) if os.path.isfile(os.path.join(img_dir, x))] + +# Get all projects, committees, podlings +cmts = requests.get('https://whimsy.apache.org/public/committee-info.json').json() +pods = requests.get('https://whimsy.apache.org/public/public_podlings.json').json() +projs = requests.get('https://projects.apache.org/json/foundation/projects.json').json() + + +# Churn out a big json blob of projects +projects = {} +for k, cmt in cmts['committees'].items(): + k = k.replace('-', '') + if k == 'httpcomponents': + k = 'hc' + el = { + 'name': cmt['display_name'], + 'established': cmt['established'], + 'description': cmt['description'], + 'website': cmt['site'], + 'podling': False, + 'has_default': False, + 'images': [] + } + projects[k] = el + +for k, cmt in pods['podling'].items(): + k = k.replace('-', '') + el = { + 'name': cmt['name'], + 'established': cmt['startdate'], + 'description': cmt['description'], + 'website': "https://%s.apache.org/" % k, + 'podling': True, + 'has_default': False, + 'images': [] + } + if cmt['status'] == "current" and k not in projects: + projects[k] = el + +for k, cmt in projs.items(): + k = k.replace('-', '') + el = { + 'name': cmt['name'].replace('Apache ', ''), + 'established': cmt.get('created', 'Sub project of %s' % cmt['pmc']), + 'description': cmt.get('description', 'No description available'), + 'website': cmt.get('homepage', 'https://www.apache.org/'), + 'podling': False, + 'has_default': False, + 'images': [] + } + if k not in projects: + k = re.sub(r"_.+", "", k) + projects[k] = el + + +# Add foundation as a project +projects['foundation'] = { + 'name': 'Software Foundation', + 'established': '1999-03', + 'description': 'Foundation logo', + 'website': "https://www.apache.org/", + 'podling': False, + 'has_default': False, + 'images': [] +} + +# Prep montage for execution later +montage = ['/usr/bin/montage', '-geometry', '200x150+4+4', '-tile', '20x'] +montage_tlps = ['/usr/bin/montage', '-geometry', '200x150+4+4', '-tile', '20x'] +montage_large = ['/usr/bin/montage', '-geometry', '1200x600+20+20', '-tile', '8x'] +montage_wide = ['/usr/bin/montage', '-geometry', '1200x600+20+20', '-tile', '15x'] + + +# Process each file... +for file in files: + m = re.match(r"^([^.-]+).*?\.(.+)$", file) + project = m.group(1) + if project not in projects: + for k in projects: + if k.endswith("-%s" % project): + project = k + break + ext = m.group(2) + oext = ext + fpath = '%s/%s' % (img_dir, file) + st = os.stat(fpath) + skipit = False + if st.st_mtime < (time.time() - 4200) and os.path.exists('%s/%s/default.png' % (out_dir, project)): + print("Skipping %s" % fpath) + skipit = True + # EPS should be converted to PDF first, or inkscape borks :/ + if ext == 'eps': + xfile = file.replace('.'+ext, '') + if not skipit and not os.path.exists('%s/%s.pdf' % (img_dir, xfile)): + subprocess.check_output(('ps2pdf', '-dPDFSETTINGS=/prepress', '-dEPSCrop', '%s/%s' % (img_dir, file), '%s/pdftmp/%s.pdf' % (img_dir, xfile))) + ext = 'pdf' + file = 'pdftmp/' + xfile + '.pdf' + # Scalable formats + if ext in ['svg', 'ai', 'pdf', 'png']: + print("Converting %s to PNG/PDF" % file) + xfile = file.replace('.'+ext, '').replace('pdftmp/', '') + ppath = "%s/%s" % (out_dir, project) + if not os.path.isdir(ppath): + os.mkdir(ppath) + try: + if xfile == project or xfile == '%s-1' % project: + if not skipit: + subprocess.check_output(('inkscape', '-z', '%s/%s' % (img_dir, file), '-e', '%s/%s/default.png' % (out_dir, project), '-w', '720')) + projects[project]['has_default'] = True + except: + pass + + # PNG, normal res + if xfile == project or xfile == '%s-1' % project: + if project != 'foundation': + montage_large.append('%s/%s/%s.png' % (out_dir, project, xfile)) + montage_wide.append('%s/%s/%s.png' % (out_dir, project, xfile)) + try: + if not skipit: + subprocess.check_output(('inkscape', '-z', '%s/%s' % (img_dir, file), '-e', '%s/%s/%s.png' % (out_dir, project, xfile), '-w', '1200')) + im = Image.open('%s/%s/%s.png' % (out_dir, project, xfile)) + w = im.width + h = im.height + projects[project]['images'].append({'original': xfile, 'name': '%s' % xfile, 'filename': '%s/%s.png' % (project, xfile), 'format': 'png', 'width': w, 'height': h}) + except: + pass + # PNG, high res + try: + if not skipit: + subprocess.check_output(('inkscape', '-z', '%s/%s' % (img_dir, file), '-e', '%s/%s/%s_highres.png' % (out_dir, project, xfile), '-w', '3600')) + im = Image.open('%s/%s/%s_highres.png' % (out_dir, project, xfile)) + w = im.width + h = im.height + projects[project]['images'].append({'original': xfile, 'name': '%s (high res)' % xfile, 'filename': '%s/%s_highres.png' % (project, xfile), 'format': 'png', 'width': w, 'height': h}) + except: + pass + try: + if not skipit: + subprocess.check_output(('inkscape', '-z', '%s/%s' % (img_dir, file), '-A', '%s/%s/%s.pdf' % (out_dir, project, xfile), '-w', '1200')) + projects[project]['images'].append({'original': xfile, 'name': xfile, 'filename': '%s/%s.pdf' % (project, xfile), 'format': 'pdf'}) + except: + pass + +with open("%s/logos.json" % out_dir, "w") as f: + json.dump(projects, f, indent = 2) + + + +for project in projects: + xp = '%s/%s/default.png' % (out_dir, project) + if os.path.exists(xp): + if project != 'foundation': + montage.append(xp) + if not projects[project]['podling']: + montage_tlps.append(xp) + +montage.append('%s../montages/standard.png' % out_dir) +montage_tlps.append('%s../montages/standard_tlps_only.png' % out_dir) +montage_large.append('%s../montages/highres_tall.png' % out_dir) +montage_wide.append('%s../montages/highres_wide.png' % out_dir) + +# Only make new montages every 12 hours +try: + st = os.stat('%s../montages/standard.png' % out_dir) +except: + st = None +if (not st) or st.st_mtime < (time.time() - 43200): + print("Making montage...") + subprocess.check_output(montage) + subprocess.check_output(montage_tlps) + print("Making montage (high res, tall)...") + subprocess.check_output(montage_large) + print("Making montage (high res, wide)...") + subprocess.check_output(montage_wide) +else: + print("Skipping montages...") + +print("The following TLPs are currently not represented: ") +for k, cmt in cmts['committees'].items(): + k = k.replace('-', '') + if not projects.get(k): + continue + if len(projects[k]['images']) == 0: + print(k)