--- /dev/null
+* annex.backend=SHA512
end
end
end
+
+ # Register URLs for git-annex keys
+ unless (uribase = ENV['ANNEX_URI_BASE'].to_s.chomp("/")).empty?
+ Open3.popen2("git", "annex", "registerurl") do |stdin, stdout, result|
+ @items.each do |item|
+ l = File.readlink(item.raw_filename)
+ next unless l =~ %r{/annex/objects/}
+
+ key = File.basename(l)
+
+ # Find output reps corresponding to this key, if any
+ item.reps.each do |rep|
+ next unless
+ FileUtils.identical?(item.raw_filename, rep.raw_path)
+
+ loop do
+ STDOUT.write(stdout.read_nonblock(100))
+ rescue EOFError, IO::WaitReadable
+ break
+ end
+
+ stdin.printf("%s %s%s\n", key, uribase, rep.path)
+ end
+ rescue Errno::EINVAL
+ end
+
+ stdin.close
+ loop do
+ STDOUT.write(stdout.readpartial(100))
+ rescue EOFError
+ break
+ end
+
+ unless (rc = result.value).success?
+ printf("git annex registerurl failed: %s\n", rc.to_s)
+ end
+ end
+ end
end
compile '/license/gpl*.md' do
write to_xhtml
end
+compile '/images/*.jpg', rep: :large do
+ filter :imgresize, width: 1200, height: 1200
+ write item.identifier.without_ext + '-t1200.' + item.identifier.ext
+end
+
+compile '/images/*.jpg', rep: :info do
+ filter :imginfo
+ layout '/imginfo.xsl'
+ layout '/default.xml'
+ layout '/default.xsl'
+ filter :relativize_paths, type: :xml
+ filter :xhtml_compat
+ filter :remove_wj
+ write to_xhtml
+end
+
compile '/**/*.scss' do
filter :sass, syntax: :scss
filter :css_source, uribase: \
--- /dev/null
+../../.git/annex/objects/JW/0W/SHA512-s2751176--43e58095d1a7a641599f648c2e3985ee166e58c0694ef53ccc64ef1027753f36f82a012f5122067b3d0230fb8570cf1167789925147ef0fadbe88b04732f9167/SHA512-s2751176--43e58095d1a7a641599f648c2e3985ee166e58c0694ef53ccc64ef1027753f36f82a012f5122067b3d0230fb8570cf1167789925147ef0fadbe88b04732f9167
\ No newline at end of file
--- /dev/null
+---
+title: ASUS K8N-E Deluxe Capacitor Locations
+copyright: 2020 Nick Bowler
+license: cc-by-sa-4.0
+description: |
+ <p>Photo with overlay marking the locations and types of all
+ electrolytic capacitors on my ASUS K8N-E Deluxe motherboard.</p>
+ <table class='cc'>
+ <thead>
+ <tr>
+ <th>Label</th>
+ <th>Qty.</th>
+ <th>Value</th>
+ <th>Dimensions</th>
+ <th>Brand</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>17</td>
+ <td>820µF,  6.3V</td>
+ <td>Pitch: 3.5mm, Diameter: 8mm, Height: 13mm</td>
+ <td>OST</td>
+ </tr>
+ <tr>
+ <td>2</td>
+ <td>6</td>
+ <td>1500µF, 6.3V</td>
+ <td>Pitch: 3.5mm, Diameter: 8mm, Height: 20mm</td>
+ <td>Ltec</td>
+ </tr>
+ <tr>
+ <td>3</td>
+ <td>3</td>
+ <td>1000µF, 16V</td>
+ <td>Pitch: 3.5mm, Diameter: 8mm, Height: 20mm</td>
+ <td>Nippon Chemi-Con</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>14</td>
+ <td>100µF,  16V</td>
+ <td>Pitch: 2.0mm, Diameter: 5mm, Height: 12mm</td>
+ <td>GSC</td>
+ </tr>
+ </tbody>
+ </table>
+ <p>Several of the OST and Ltec (the latter obscured by the heatsink in
+ the photo) capacitors have obvious signs of catastrophic failure.
+ The other types show no obvious damage.</p>
$linkvisitedcolour: #800080;
$ruledefaultcolour: #d3d3d3;
+$rulestrongcolour: #696969;
$annotationcolour: #708090;
+$tableshadecolour: #f5f5f5;
+
@mixin header_size($maxwidth, $fontsize) {
font-size: $fontsize;
max-width: 1em * ($maxwidth / $fontsize);
h1 { @include header_size(60em, 2em); }
h2 { @include header_size(60em, 1.5em); }
+p>img { max-width: 40em; width: 100%; height: auto; }
+
p, dt, dd, li {
text-align: justify;
padding: 0;
margin: 0;
}
-p, div, ul, ol, dl, hr {
+p, table, div, ul, ol, dl, hr {
max-width: 50em;
padding: 0;
margin: 0;
}
-p, body>div { margin: 1em 0; }
+p, table, body>div { margin: 1em 0; }
li { margin: 0 0 0 2em; }
dd { margin: 0 0 0 1em; }
.permalink { visibility: hidden; }
}
+// General table styles.
+table {
+ border: 1px solid $ruledefaultcolour;
+ border-collapse: collapse;
+ width: 100%;
+}
+
+table>* { font-size: 0.9em; }
+caption {
+ caption-side: top;
+ font-weight: bold;
+ font-size: 1em;
+ text-align: left;
+ margin: 0 0 0.5em 0;
+}
+
+td, th {
+ vertical-align: middle;
+ text-align: left;
+ padding: 1ex;
+ margin: 0;
+}
+
+thead>tr, tbody>tr { border: solid $ruledefaultcolour; }
+th, thead>tr { border-bottom: 1px solid $rulestrongcolour; }
+*>table, *>th { border: none; }
+thead>tr { border-width: 1px; }
+tbody>tr { border-width: 0 1px; }
+
+td + td { box-shadow: -1px 0 $backgroundcolour; }
+
+tbody>tr {
+ &:nth-of-type(even) { background-color: $tableshadecolour; }
+ &:last-child { border-bottom: solid 1px $ruledefaultcolour; }
+}
+
+// Specific table styles
+table.cc {
+ &>tr>*:first-child, &>*>tr>*:first-child {
+ &+* { text-align: center; }
+ text-align: center;
+ }
+}
+
// Site header rules
#breadcrumbs>*, #sitetitle>* { font-size: 0.8em; }
#breadcrumbs {
--- /dev/null
+<?xml version='1.0' encoding='UTF-8' ?>
+<!--
+ Nick's web site: Image description page formatter
+
+ Copyright © 2020 Nick Bowler
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>
+-->
+<xsl:stylesheet version='1.0'
+ xmlns='http://www.w3.org/1999/xhtml'
+ xmlns:xhtml='http://www.w3.org/1999/xhtml'
+ xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
+ exclude-result-prefixes='xhtml'>
+
+<xsl:output method='xml' encoding='UTF-8' indent='yes'
+ omit-xml-declaration='yes' />
+
+<xsl:template match='node()|@*'>
+ <xsl:copy><xsl:apply-templates select='node()|@*' /></xsl:copy>
+</xsl:template>
+
+<xsl:template name='exif'>
+ <xsl:param name='node' select='.' />
+ <xsl:param name='name' select='local-name($node)' />
+
+ <tr>
+ <td><xsl:value-of select='$name' /></td>
+ <td><xsl:value-of select='$node' /></td>
+ </tr>
+</xsl:template>
+<xsl:template match='exif'>
+ <h2>Metadata</h2>
+ <table>
+ <thead>
+ <tr><th>Attribute</th><th>Value</th></tr>
+ </thead>
+ <tbody>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='make' />
+ <xsl:with-param name='name' select='"Camera make"' />
+ </xsl:call-template>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='model' />
+ <xsl:with-param name='name' select='"Camera model"' />
+ </xsl:call-template>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='date_time_original' />
+ <xsl:with-param name='name' select='"Date taken"' />
+ </xsl:call-template>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='concat(exposure_time, "s")' />
+ <xsl:with-param name='name' select='"Shutter speed"' />
+ </xsl:call-template>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='concat("f/", f_number)' />
+ <xsl:with-param name='name' select='"Aperture"' />
+ </xsl:call-template>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='exposure_bias_value' />
+ <xsl:with-param name='name' select='"Exposure compensation"' />
+ </xsl:call-template>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='concat(focal_length, "mm")' />
+ <xsl:with-param name='name' select='"Focal length"' />
+ </xsl:call-template>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='flash' />
+ <xsl:with-param name='name' select='"Flash"' />
+ </xsl:call-template>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='iso_speed_ratings' />
+ <xsl:with-param name='name' select='"ISO speed rating"' />
+ </xsl:call-template>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='exposure_program' />
+ <xsl:with-param name='name' select='"Exposure program"' />
+ </xsl:call-template>
+ <xsl:call-template name='exif'>
+ <xsl:with-param name='node' select='metering_mode' />
+ <xsl:with-param name='name' select='"Metering mode"' />
+ </xsl:call-template>
+ </tbody>
+ </table>
+</xsl:template>
+
+<xsl:template match='variant'>
+ <li>
+ <a href='{uri}'>
+ <xsl:value-of
+ select='concat(name, " (", width, "x", height, ", ", filesize, ")")' />
+ </a>
+ </li>
+</xsl:template>
+
+<xsl:template match='xhtml:description'>
+ <h2 id='desc'>Description</h2>
+ <xsl:choose>
+ <xsl:when test='*'>
+ <xsl:apply-templates select='node()' />
+ </xsl:when>
+ <xsl:otherwise>
+ <p><xsl:apply-templates select='node()' /></p>
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+
+<xsl:template match='/'>
+ <p>
+ <img src='{/image/variant[1]/uri}' alt=''
+ width='{/image/variant[1]/width}'
+ height='{/image/variant[1]/height}'>
+ <xsl:if test='/image/xhtml:description'>
+ <xsl:attribute name='longdesc'>#desc</xsl:attribute>
+ </xsl:if>
+ </img>
+ </p>
+ <xsl:apply-templates select='/image/xhtml:description' />
+ <h2>Files</h2>
+ <ul>
+ <xsl:apply-templates select='/image/variant'>
+ <xsl:sort select='width*height' order='ascending' data-type='number' />
+ </xsl:apply-templates>
+ </ul>
+ <xsl:apply-templates select='/image/exif' />
+</xsl:template>
+
+</xsl:stylesheet>
p = xml.xpath('//xhtml:p', Xmlns)
if p.empty? then nil else p[0].xpath('string(.)') end
end
+
+def human_filesize(size)
+ units = ["B", "KiB", "MiB", "GiB"]
+
+ for unit in units
+ if (size < 1024)
+ break
+ end
+
+ size /= 1024.0
+ end
+
+ sprintf("%.1f %s", size + 0.05, unit)
+end
--- /dev/null
+# Nick's web site: imginfo filter. Generate XML representation of image
+# metadata which can be further processed into a web page.
+#
+# Copyright © 2020 Nick Bowler
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+class ImgInfoFilter < Nanoc::Filter
+ identifier :imginfo
+ type :binary => :text
+
+ require 'exifr/jpeg'
+ require 'fastimage'
+
+ def do_variant(xml, name, item = @item, rep: :default)
+ file = item.reps[rep].raw_path
+
+ w, h = FastImage.size(file)
+ sz = File.size(file)
+
+ xml.variant {
+ xml.name(name)
+ xml.uri(item_uri(item, rep: rep))
+ xml.width(w)
+ xml.height(h)
+ xml.filesize(human_filesize(sz))
+ }
+ end
+
+ def run(filename, params = {})
+ exif = EXIFR::JPEG.new(filename).to_hash
+
+ b = Nokogiri::XML::Builder.new do |xml|
+ xml.image {
+ do_variant(xml, "Large", rep: :large)
+ do_variant(xml, "Original")
+
+
+ if @item[:description]
+ xml.description(:xmlns => 'http://www.w3.org/1999/xhtml') {
+ xml << @item[:description]
+ }
+ end
+
+ xml.exif {
+ exif.each do |key, value|
+ # Convert some fields to more useful forms...
+ case key
+ when :f_number, :exposure_bias_value
+ value = sprintf("%.1f", value)
+ when :focal_length
+ value = sprintf("%d\n", value)
+ when :gps_version_id
+ value = value.bytes.join(".")
+ when :exposure_program
+ case value
+ when 1 then value = "Manual"
+ when 2 then value = "Normal program"
+ when 3 then value = "Aperture priority"
+ when 4 then value = "Shutter priority"
+ end
+ when :metering_mode
+ case value
+ when 1 then value = "Average"
+ when 2 then value = "Center weighted average"
+ when 3 then value = "Spot"
+ when 4 then value = "Multi-spot"
+ when 5 then value = "Pattern"
+ when 6 then vlaue = "Partial"
+ end
+ when :flash
+ tmp = if value & 1 == 1 then "Yes" else "No" end
+ case (value >> 3) & 3
+ when 1, 2 then tmp += ", compulsory"
+ when 3 then tmp += ", auto"
+ end
+ case (value >> 1) & 3
+ when 2 then tmp += ", return light not detected"
+ when 3 then tmp += ", return light detected"
+ end
+ value = tmp
+ end
+
+ case value
+ when String
+ value.delete!("\x00")
+ value.strip!
+ when Time
+ # EXIF does not do timezones so don't display one
+ value = value.strftime("%Y-%m-%d %H:%M:%S")
+ end
+
+ xml.send((key.to_s << "_").to_sym, value.to_s)
+ end
+ }
+ }
+ end
+ b.to_xml
+ end
+end
--- /dev/null
+# Nick's web site: imgresize filter. Helper for resizing images during site
+# compilations for thumbnails, etc.
+#
+# Copyright © 2016, 2020 Nick Bowler
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+class ImgResize < Nanoc::Filter
+ identifier :imgresize
+ type :binary
+
+ def run(filename, params = {})
+ w = if params[:width] then params[:width].to_i end
+ h = if params[:height] then params[:height].to_i end
+ scale = [w, h && "x", h].join
+
+ args = ["-scale", scale, filename]
+ case filename
+ when /\.jpg$/
+ args << "-quality" << "85"
+ end
+ args << output_filename
+
+ system('gm', 'convert', *args)
+ end
+end