CINXE.COM
Development - ISFDB
<!DOCTYPE html> <html class="client-nojs" lang="en" dir="ltr"> <head> <meta charset="UTF-8"/> <title>Development - ISFDB</title> <script>document.documentElement.className="client-js";RLCONF={"wgBreakFrames":!1,"wgSeparatorTransformTable":["",""],"wgDigitTransformTable":["",""],"wgDefaultDateFormat":"dmy","wgMonthNames":["","January","February","March","April","May","June","July","August","September","October","November","December"],"wgRequestId":"Z9d2x3QCjzH68zqtavPDPAAAA5g","wgCSPNonce":!1,"wgCanonicalNamespace":"","wgCanonicalSpecialPageName":!1,"wgNamespaceNumber":0,"wgPageName":"Development","wgTitle":"Development","wgCurRevisionId":709235,"wgRevisionId":709235,"wgArticleId":21127,"wgIsArticle":!0,"wgIsRedirect":!1,"wgAction":"view","wgUserName":null,"wgUserGroups":["*"],"wgCategories":["Pages using deprecated source tags","Pages using deprecated enclose attributes"],"wgPageContentLanguage":"en","wgPageContentModel":"wikitext","wgRelevantPageName":"Development","wgRelevantArticleId":21127,"wgIsProbablyEditable":!1,"wgRelevantPageIsProbablyEditable":!1,"wgRestrictionEdit":[],"wgRestrictionMove":[ ]};RLSTATE={"site.styles":"ready","noscript":"ready","user.styles":"ready","user":"ready","user.options":"loading","ext.pygments":"ready","skins.vector.styles.legacy":"ready","mediawiki.toc.styles":"ready"};RLPAGEMODULES=["site","mediawiki.page.startup","mediawiki.page.ready","mediawiki.toc","skins.vector.legacy.js"];</script> <script>(RLQ=window.RLQ||[]).push(function(){mw.loader.implement("user.options@1hzgi",function($,jQuery,require,module){/*@nomin*/mw.user.tokens.set({"patrolToken":"+\\","watchToken":"+\\","csrfToken":"+\\"}); });});</script> <link rel="stylesheet" href="/wiki/load.php?lang=en&modules=ext.pygments%7Cmediawiki.toc.styles%7Cskins.vector.styles.legacy&only=styles&skin=vector"/> <script async="" src="/wiki/load.php?lang=en&modules=startup&only=scripts&raw=1&skin=vector"></script> <meta name="generator" content="MediaWiki 1.35.6"/> <link rel="shortcut icon" href="/favicon.ico"/> <link rel="search" type="application/opensearchdescription+xml" href="/wiki/opensearch_desc.php" title="ISFDB (en)"/> <link rel="EditURI" type="application/rsd+xml" href="https://isfdb.org/wiki/api.php?action=rsd"/> <link rel="license" href="/wiki/index.php/Creative_Commons_License"/> <link rel="alternate" type="application/atom+xml" title="ISFDB Atom feed" href="/wiki/index.php?title=Special:RecentChanges&feed=atom"/> <!--[if lt IE 9]><script src="/wiki/resources/lib/html5shiv/html5shiv.js"></script><![endif]--> </head> <body class="mediawiki ltr sitedir-ltr mw-hide-empty-elt ns-0 ns-subject page-Development rootpage-Development skin-vector action-view skin-vector-legacy"> <div id="mw-page-base" class="noprint"></div> <div id="mw-head-base" class="noprint"></div> <div id="content" class="mw-body" role="main"> <a id="top"></a> <div id="siteNotice" class="mw-body-content"></div> <div class="mw-indicators mw-body-content"> </div> <h1 id="firstHeading" class="firstHeading" lang="en">Development</h1> <div id="bodyContent" class="mw-body-content"> <div id="siteSub" class="noprint">From ISFDB</div> <div id="contentSub"></div> <div id="contentSub2"></div> <div id="jump-to-nav"></div> <a class="mw-jump-link" href="#mw-head">Jump to navigation</a> <a class="mw-jump-link" href="#searchInput">Jump to search</a> <div id="mw-content-text" lang="en" dir="ltr" class="mw-content-ltr"><div class="mw-parser-output"><table class="wikitable" style="margin: 0 auto; float:left; clear:none; background:#FCFED4; border:2px solid #FAD6A5; text-align:center; margin-bottom:10px;"> <tbody><tr> <th colspan="5" style="background:#FAD6A5; font-size:140%; color:#6C410B;"><b>ISFDB Discussion Pages and Noticeboards</b> </th></tr> <tr> <td colspan="5"><b>Before posting to this page, consider whether one of the other discussion pages or noticeboards might suit your needs better.<br />If you're looking for help remembering a book title, check out the resources in <a href="/wiki/index.php/ISFDB:FAQ#I_need_help_finding_a_book" title="ISFDB:FAQ">our FAQ</a>.<br />Please also see <a href="/wiki/index.php/Help:Contents" title="Help:Contents">our Help pages</a>.</b> </td></tr> <tr> <td style="width:20%; vertical-align:top; border:2px solid #FAD6A5; background:white;"><span style="font-size:120%;"><b><a href="/wiki/index.php/ISFDB:Help_desk" title="ISFDB:Help desk">Help desk</a></b></span><br />Questions about doing a specific task, or how to correct information when the solution is not immediately obvious. <br /><span style="padding:0 1em 0 1em; float:left; font-size:90%;">• <a rel="nofollow" class="external text" href="http://www.isfdb.org/wiki/index.php?title=ISFDB:Help_desk&action=edit&section=new">New post</a> • <a href="/wiki/index.php/ISFDB:Help_desk/archives" title="ISFDB:Help desk/archives">Archives</a></span> </td> <td style="width:20%; vertical-align:top; border:2px solid #FAD6A5; background:white;"><span style="font-size:120%;"><b><a href="/wiki/index.php/ISFDB:Research_Assistance" title="ISFDB:Research Assistance">Research Assistance</a></b></span><br />Help with bibliographic projects.<br /><span style="padding:0 1em 0 1em; float:right; font-size:90%;">• <a rel="nofollow" class="external text" href="http://www.isfdb.org/wiki/index.php?title=ISFDB:Research_Assistance&action=edit&section=new">New post</a> • <a href="/wiki/index.php/ISFDB:Research_Assistance/Archives" title="ISFDB:Research Assistance/Archives">Archives</a></span> </td> <td style="width:20%; vertical-align:top; border:2px solid #FAD6A5; background:white;"><span style="font-size:120%;"><b><a href="/wiki/index.php/Rules_and_standards_discussions" title="Rules and standards discussions">Rules and standards</a></b></span><br />Discussions about the rules and standards, as well as questions about interpretation and application of those rules.<br /><span style="padding:0 1em 0 1em; float:right; font-size:90%;">• <a rel="nofollow" class="external text" href="http://www.isfdb.org/wiki/index.php?title=Rules_and_standards_discussions&action=edit&section=new">New post</a> • <a href="/wiki/index.php/Rules_and_standards_changelog" title="Rules and standards changelog">Rules changelog</a> • <a href="/wiki/index.php/Rules_and_standards_discussions/Archive" title="Rules and standards discussions/Archive">Archives</a></span> </td> <td style="width:20%; vertical-align:top; border:2px solid #FAD6A5; background:white;"><span style="font-size:120%;"><b><a href="/wiki/index.php/ISFDB:Community_Portal" title="ISFDB:Community Portal">Community Portal</a></b></span><br />General discussion about anything not covered by the more specialized noticeboards to the left.<br /><span style="padding:0 1em 0 1em; float:right; font-size:90%;">• <a rel="nofollow" class="external text" href="http://www.isfdb.org/wiki/index.php?title=ISFDB:Community_Portal&action=edit&section=new">New post</a> • <a href="/wiki/index.php/ISFDB:Community_Portal/Archive" title="ISFDB:Community Portal/Archive">Archives</a></span> </td> <td style="width:20%; vertical-align:top; border:2px solid #FAD6A5; background:white;"><span style="font-size:120%;"><b><a href="/wiki/index.php/ISFDB:Moderator_noticeboard" title="ISFDB:Moderator noticeboard">Moderator noticeboard</a></b></span><br />Get the attention of moderators regarding submission questions. <br /> <br /><span style="padding:0 1em 0 1em; float:right; font-size:90%;">• <a rel="nofollow" class="external text" href="http://www.isfdb.org/wiki/index.php?title=ISFDB:Moderator_noticeboard&action=edit&section=new">New post</a> • <a href="/wiki/index.php/ISFDB:Moderator_noticeboard/Archives" title="ISFDB:Moderator noticeboard/Archives">Archives</a> • <a rel="nofollow" class="external text" href="http://www.isfdb.org/cgi-bin/myrecent.cgi?0+N">Cancel submission</a></span> </td></tr> <tr> <td colspan="5"><b>Roadmap:</b> For the original discussion of Roadmap 2017 see <a href="/wiki/index.php/ISFDB:Community_Portal/Archive/Archive42#Roadmap_2017" title="ISFDB:Community Portal/Archive/Archive42">this archived section</a>. For the current implementation status, see <a href="/wiki/index.php/What%27s_New#Roadmap_2017" title="What's New">What's New#Roadmap 2017</a>. </td></tr></tbody></table> <p><br /> </p><p><br /> </p> <div style="width:250px; border:solid #6C410B 1px; background-color:#FCFED4; text-align:left; float:right; padding:5px; font-size:90%;"> <p><b>Related resources:</b> </p> <ul><li>SourceForge: <a rel="nofollow" class="external text" href="https://sourceforge.net/p/isfdb/">ISFDB Bibliographic Tools</a> <ul><li>repo viewer: <a rel="nofollow" class="external text" href="https://sourceforge.net/p/isfdb/code-svn">source code</a></li> <li><a rel="nofollow" class="external text" href="https://sourceforge.net/p/isfdb/discussion/">discussion</a></li> <li><a rel="nofollow" class="external text" href="https://sourceforge.net/p/isfdb/_list/tickets">tickets</a> <ul><li><a rel="nofollow" class="external text" href="https://sourceforge.net/p/isfdb/bugs/">Bugs</a></li> <li><a rel="nofollow" class="external text" href="https://sourceforge.net/p/isfdb/support-requests/">Support Requests</a></li> <li><a rel="nofollow" class="external text" href="https://sourceforge.net/p/isfdb/patches/">Patches</a></li> <li><a rel="nofollow" class="external text" href="https://sourceforge.net/p/isfdb/feature-requests/">Feature Requests</a></li></ul></li></ul></li> <li>Obsolete historic issues <ul><li><a href="/wiki/index.php/ISFDB_Bug_List" title="ISFDB Bug List">ISFDB Bug List</a></li> <li><a href="/wiki/index.php/ISFDB_Feature_List" title="ISFDB Feature List">ISFDB Feature List</a></li></ul></li> <li><a href="/wiki/index.php/ISFDB:Proposed_Design_Changes" title="ISFDB:Proposed Design Changes">ISFDB:Proposed Design Changes</a></li> <li><a href="/wiki/index.php/ISFDB:Proposed_Interface_Changes" title="ISFDB:Proposed Interface Changes">ISFDB:Proposed Interface Changes</a></li> <li><a href="/wiki/index.php/Development/Recent_Patches" title="Development/Recent Patches">Recent Patch list</a> (<a href="/wiki/index.php/Development/Archive" title="Development/Archive">archive</a>)</li> <li><a href="/wiki/index.php/User_talk:Fixer" title="User talk:Fixer">Fixer's Talk page</a> (for Fixer-related issues)</li> <li><a href="/wiki/index.php/ISFDB_Design_Documentation" title="ISFDB Design Documentation">ISFDB Design Documentation</a> (some parts are still being brought up-to-date)</li> <li><a href="/wiki/index.php/Database_Schema" title="Database Schema">Database Schema</a></li> <li><a href="/wiki/index.php/ISFDB_Downloads" title="ISFDB Downloads">ISFDB Downloads</a> (contains links to the installation instructions)</li> <li><a href="/wiki/index.php/ISFDB_Build_Process" title="ISFDB Build Process">ISFDB Build Process</a> (explanation of the build/install process)</li> <li><a href="/wiki/index.php/ISFDB_Page_Map" title="ISFDB Page Map">ISFDB Page Map</a> — a list of which pages link to which other pages</li></ul> </div> <p>This page serves as the hub for discussing ISFDB-related software development. </p> <div id="toc" class="toc" role="navigation" aria-labelledby="mw-toc-heading"><input type="checkbox" role="button" id="toctogglecheckbox" class="toctogglecheckbox" style="display:none" /><div class="toctitle" lang="en" dir="ltr"><h2 id="mw-toc-heading">Contents</h2><span class="toctogglespan"><label class="toctogglelabel" for="toctogglecheckbox"></label></span></div> <ul> <li class="toclevel-1 tocsection-1"><a href="#Developers_and_Testers"><span class="tocnumber">1</span> <span class="toctext">Developers and Testers</span></a></li> <li class="toclevel-1 tocsection-2"><a href="#Software_Development_Process"><span class="tocnumber">2</span> <span class="toctext">Software Development Process</span></a></li> <li class="toclevel-1 tocsection-3"><a href="#Git_Development_Process"><span class="tocnumber">3</span> <span class="toctext">Git Development Process</span></a></li> <li class="toclevel-1 tocsection-4"><a href="#Changes_and_Patches"><span class="tocnumber">4</span> <span class="toctext">Changes and Patches</span></a> <ul> <li class="toclevel-2 tocsection-5"><a href="#Recent_Patches"><span class="tocnumber">4.1</span> <span class="toctext">Recent Patches</span></a></li> <li class="toclevel-2 tocsection-6"><a href="#Outstanding_changes"><span class="tocnumber">4.2</span> <span class="toctext">Outstanding changes</span></a></li> <li class="toclevel-2 tocsection-7"><a href="#Planned_changes"><span class="tocnumber">4.3</span> <span class="toctext">Planned changes</span></a></li> </ul> </li> <li class="toclevel-1 tocsection-8"><a href="#Current_Activity"><span class="tocnumber">5</span> <span class="toctext">Current Activity</span></a> <ul> <li class="toclevel-2 tocsection-9"><a href="#HTTPS_Migration"><span class="tocnumber">5.1</span> <span class="toctext">HTTPS Migration</span></a></li> <li class="toclevel-2 tocsection-10"><a href="#MartyD"><span class="tocnumber">5.2</span> <span class="toctext">MartyD</span></a></li> <li class="toclevel-2 tocsection-11"><a href="#Python3"><span class="tocnumber">5.3</span> <span class="toctext">Python3</span></a></li> </ul> </li> <li class="toclevel-1 tocsection-12"><a href="#Development_Process"><span class="tocnumber">6</span> <span class="toctext">Development Process</span></a> <ul> <li class="toclevel-2 tocsection-13"><a href="#General_Principles"><span class="tocnumber">6.1</span> <span class="toctext">General Principles</span></a></li> <li class="toclevel-2 tocsection-14"><a href="#Coding_style"><span class="tocnumber">6.2</span> <span class="toctext">Coding style</span></a></li> <li class="toclevel-2 tocsection-15"><a href="#Where_Are_the_Globally_Scoped_Variables_defined.3F"><span class="tocnumber">6.3</span> <span class="toctext">Where Are the Globally Scoped Variables defined?</span></a></li> <li class="toclevel-2 tocsection-16"><a href="#Code_Format"><span class="tocnumber">6.4</span> <span class="toctext">Code Format</span></a> <ul> <li class="toclevel-3 tocsection-17"><a href="#Indentation"><span class="tocnumber">6.4.1</span> <span class="toctext">Indentation</span></a></li> <li class="toclevel-3 tocsection-18"><a href="#Other_Standards"><span class="tocnumber">6.4.2</span> <span class="toctext">Other Standards</span></a></li> </ul> </li> <li class="toclevel-2 tocsection-19"><a href="#How_to_Add_a_New_Cleanup_Report"><span class="tocnumber">6.5</span> <span class="toctext">How to Add a New Cleanup Report</span></a></li> <li class="toclevel-2 tocsection-20"><a href="#How_to_Add_a_new_Field_to_Title_records"><span class="tocnumber">6.6</span> <span class="toctext">How to Add a new Field to Title records</span></a></li> <li class="toclevel-2 tocsection-21"><a href="#How_to_Add_a_New_External_ID_Type"><span class="tocnumber">6.7</span> <span class="toctext">How to Add a New External ID Type</span></a></li> <li class="toclevel-2 tocsection-22"><a href="#How_to_Add_a_New_Banner_Image"><span class="tocnumber">6.8</span> <span class="toctext">How to Add a New Banner Image</span></a></li> <li class="toclevel-2 tocsection-23"><a href="#How_to_Add_a_New_Format_Code"><span class="tocnumber">6.9</span> <span class="toctext">How to Add a New Format Code</span></a></li> <li class="toclevel-2 tocsection-24"><a href="#How_to_Synchronize_ISFDB.27s_ISBN_ranges_with_the_International_ISBN_Agency"><span class="tocnumber">6.10</span> <span class="toctext">How to Synchronize ISFDB's ISBN ranges with the International ISBN Agency</span></a></li> <li class="toclevel-2 tocsection-25"><a href="#Duplicate_Functions_and_Duplicate_Filenames"><span class="tocnumber">6.11</span> <span class="toctext">Duplicate Functions and Duplicate Filenames</span></a></li> </ul> </li> <li class="toclevel-1 tocsection-26"><a href="#Related_Projects"><span class="tocnumber">7</span> <span class="toctext">Related Projects</span></a></li> </ul> </div> <h2><span class="mw-headline" id="Developers_and_Testers">Developers and Testers</span></h2> <ul><li><a href="/wiki/index.php/User:MartyD" title="User:MartyD">MartyD</a> — developer</li> <li><a href="/wiki/index.php/User:Ahasuerus" title="User:Ahasuerus">Ahasuerus</a> — developer, tester and installer/administrator</li> <li><a href="/wiki/index.php/User:Alvonruff" title="User:Alvonruff">Alvonruff</a> — developer and administrator</li></ul> <h2><span class="mw-headline" id="Software_Development_Process">Software Development Process</span></h2> <p>At this time the development process works as follows: </p> <ul><li>A Bug, Support Request ("SR") or Feature Request ("FR") is created in <a rel="nofollow" class="external text" href="https://sourceforge.net/projects/isfdb/">SourceForge</a>. Anyone can do it, even "anonymous".</li> <li>FRs should be discussed on the <a href="/wiki/index.php/ISFDB:Community_Portal" title="ISFDB:Community Portal">ISFDB:Community Portal</a> and approved by the community before the work begins. Obvious bugs can be fixed and submitted without a prior discussion.</li> <li>Once a developer decides to work on a Bug/SR/FR, s/he identifies the scripts that are affected and lists the Bug/SR/FR along with the scripts on the Development page under "Outstanding Changes". This helps avoid effort duplication.</li> <li>The developer makes changes on his or her development server and tests them. S/he then sends to the ISFDB administrator (Ahasuerus since 2009), who tests them on his local development server. In some cases the administrator may ask another developer to test the changes.</li> <li>If everything works fine, the administrator commits the changes to the SourceForge repository using the SVN "commit" command, e.g.: <ul><li><div class="mw-highlight mw-highlight-lang-bash mw-content-ltr" dir="ltr"><pre><span></span>svn commit -m <span class="s2">"FR 1099 Add Last Activity date to 'Top Contributor/Moderator/etc' lists - Part 1"</span> </pre></div></li></ul></li> <li>The administrator gets the latest revision number from the SourceForge repository: <ul><li><div class="mw-highlight mw-highlight-lang-bash mw-content-ltr" dir="ltr"><pre><span></span>svn info --show-item<span class="o">=</span>revision -r HEAD </pre></div></li></ul></li> <li>The administrator creates a deployable tarball file from the modified source files, e.g: <ul><li><div class="mw-highlight mw-highlight-lang-bash mw-content-ltr" dir="ltr"><pre><span></span>tar -cvf ~/patches/3.tar biblio/toptaggers.py </pre></div> where '3' is the revision number retrieved in the previous step</li></ul></li> <li>The administrator copies the tarball to the ISFDB server and moves it to <code>/home/avonruff/isfdb2/</code>, where the main copy of the source code currently resides</li> <li>The administrator untars the tarball and types <code>make install</code> (or <code>make -B install</code> if the patch added new scripts or otherwise requires a complete rebuild)</li> <li>The administrator gzips the tarball and moves it to the archive area</li> <li>The administrator marks the Bug(s)/SR(s)/FR(s) as "Fixed/Completed" in SourceForge</li> <li>The administrator moves the completed change(s) from the list of Outstanding Changes on the Development page to the "Recent Patches" sub-page. "Recent Changes" covers all builds for the current year, so it's a useful page for developers to review.</li></ul> <h2><span class="mw-headline" id="Git_Development_Process">Git Development Process</span></h2> <p>Changes for python3 are extensive, and are stored on github. Read the <a href="/wiki/index.php/Git_Process" title="Git Process">Git Process</a> doc for details. </p> <h2><span class="mw-headline" id="Changes_and_Patches">Changes and Patches</span></h2> <h3><span class="mw-headline" id="Recent_Patches">Recent Patches</span></h3> <p><a href="/wiki/index.php/Development/Archive" title="Development/Archive">Patch Archive for 2009–2019</a> </p><p>See <a href="/wiki/index.php/Development/Recent_Patches" title="Development/Recent Patches">Development/Recent Patches</a> for the list of changes implemented recently. </p> <h3><span class="mw-headline" id="Outstanding_changes">Outstanding changes</span></h3> <table class="wikitable"> <tbody><tr> <th>Bug or Feature </th> <th width="40%">Description </th> <th>Modules and versions </th> <th>Developer </th> <th>Tester </th> <th>Date Passed </th> <th>Patch </th></tr></tbody></table> <h3><span class="mw-headline" id="Planned_changes">Planned changes</span></h3> <table class="wikitable"> <tbody><tr> <th>Bug or Feature </th> <th width="40%">Description </th> <th>Modules and versions </th> <th>Developer </th> <th>Tester </th> <th>Date Passed </th> <th>Patch </th></tr> <tr> <td><a rel="nofollow" class="external text" href="https://sourceforge.net/p/isfdb/support-requests/24">SR 24</a> </td> <td>Static and dynamic content cannot be "rehomed" correctly </td> <td> <ul><li><b>TBD</b></li></ul> </td> <td><a href="/wiki/index.php/User:Uzume" title="User:Uzume">Uzume</a> </td> <td> </td> <td> </td> <td> </td></tr></tbody></table> <h2><span class="mw-headline" id="Current_Activity">Current Activity</span></h2> <h3><span class="mw-headline" id="HTTPS_Migration">HTTPS Migration</span></h3> <p>See <a href="/wiki/index.php/Development/HTTPS" title="Development/HTTPS">Development/HTTPS</a>, <a href="/wiki/index.php/User:Alvonruff/HTTPS_Notes" title="User:Alvonruff/HTTPS Notes">User:Alvonruff/HTTPS Notes</a>, and <a href="/wiki/index.php/User:Alvonruff/ISFDB_Move" title="User:Alvonruff/ISFDB Move">User:Alvonruff/ISFDB Move</a>. The auto-renewal of certs is still an open item, and I am generally unsatisfied with the cookie-cutter, copy-and-paste methodology I used to get the current HTTPS solution running. Some deeper expertise needs to be cultivated. --<a href="/wiki/index.php/User:Alvonruff" title="User:Alvonruff">Alvonruff</a> (<a href="/wiki/index.php/User_talk:Alvonruff" title="User talk:Alvonruff">talk</a>) 11:01, 16 September 2022 (EDT) </p> <h3><span class="mw-headline" id="MartyD">MartyD</span></h3> <p>Concentrating on bugs, clean-up/consolidation, and small features. If anything ever comes of the tagging discussion at <a href="/wiki/index.php/ISFDB:Community_Portal/Archive/Archive14#Title_type_tags_in_bibliography_display" title="ISFDB:Community Portal/Archive/Archive14">ISFDB:Community Portal/Archive/Archive14#Title type tags in bibliography display</a>, I will revisit the tagging used, too. </p> <h3><span class="mw-headline" id="Python3">Python3</span></h3> <p>After a long absence, I'm coming back to the Python3 port, which is essentially working at isfdb2.org, but the source code doesn't officially exist online anywhere yet. Since the isfdb consists mostly of database and print formatting algorithms, and python3 essentially touches all of the database and print formatting algorithms, it should come as no surprise that almost every line of code is touched (especially since python3 is strict about mixed tabs/spaces in the same file). That makes it a bit awkward to directly integrate into the current codebase without causing a huge disturbance. </p><p>As such I'm going to make a git repo on github to hold the porting work. This will cause some difficulties later, as work will continue on Sourceforge with the existing codebase, so some divergence will occur. Work could progress in phases, with each phase integrated back into SVN, but that should be discussed. On the other hand, most projects have moved on from SVN on SourceForge to git on github, so that's another topic we should also discuss. </p><p>The first step in the port is converting every file to an indentation standard of strictly 8 spaces. Python3 will not run code with mixed tabs/spaces, which affects almost every file in our system. So I know we sorta settled on 8 spaces on this wiki page, but I want to make sure that everyone is actually cool with 8 space, and not 6, tabs, or whatever (I'm a tab guy, which is why there is mixed indentation in the first place, but I'll go with the majority). <a href="/wiki/index.php/User:Alvonruff" title="User:Alvonruff">Alvonruff</a> (<a href="/wiki/index.php/User_talk:Alvonruff" title="User talk:Alvonruff">talk</a>) 18:46, 8 February 2025 (EST) </p> <dl><dd>Welcome back! A few thoughts: <ul><li>We'll want to decide which version of Python3 we want to adopt. I am using 3.9.16 for the Fixer rewrite and I have repeatedly run into minor (and sometimes not so minor) Python features which were either introduced or deprecated in 3.6, 3.9, etc.</li> <li>Re: "work will continue on Sourceforge with the existing codebase", for the last 18 months my work on the core code has been anemic at best as can be seen over on <a href="/wiki/index.php/Development/Recent_Patches" title="Development/Recent Patches">Development/Recent Patches</a>. Commits have been almost entirely based on editor/moderator feedback -- new/enhanced yellow warnings on moderator review pages, table maintenance for External IDs and ISBN ranges, cleanup report tweaks, etc. The main reason is that I need to migrate Fixer to Python/MySQL by October 2025 when Microsoft stops supporting Windows 10. I have been working on it, on and off, for a number of years, but this inflexible Microsoft-imposed deadline has made it my top priority with everything else put on the back burner. (You can find the gory details over on <a href="/wiki/index.php/User:Fixer/Python_MySQL_Migration" title="User:Fixer/Python MySQL Migration">User:Fixer/Python MySQL Migration</a>.) The slowdown is unfortunate, but it also means that the code base is relatively stable, which should make it easier to migrate the software to Python 3 while I am busy with the Fixer rewrite.</li> <li>Re: git vs. SVN, I am not familiar with git, but I am sure I can figure it out if we decide to migrate to it. Back when Sourforge stopped supporting CVS, I had to choose between SVN and git. I chose SVN because it was less complex, but it's just a matter of acclimatization.</li> <li>Re: tabs vs. spaces, I am used to 8 spaces, but, again, it's not that big a deal. If I recall correctly, early on I ran into some issues with then-current versions of IDLE and tab settings, but I assume they have been fixed by now.</li></ul></dd> <dd><a href="/wiki/index.php/User:Ahasuerus" title="User:Ahasuerus">Ahasuerus</a> (<a href="/wiki/index.php/User_talk:Ahasuerus" title="User talk:Ahasuerus">talk</a>) 20:50, 8 February 2025 (EST)</dd></dl> <h2><span class="mw-headline" id="Development_Process">Development Process</span></h2> <h3><span class="mw-headline" id="General_Principles">General Principles</span></h3> <p>The ISFDB code base is over 5MB in size and has a number of dependencies, which are not always obvious. For this reason, developers should follow the "if it ain't broken, don't fix it" principle. Developers should also try to address one problem at a time. If a feature or a bug fix requires mass changes, discuss it with other developers and the administrator first. </p> <h3><span class="mw-headline" id="Coding_style">Coding style</span></h3> <p>Among the developers, there is a wide variety of backgrounds and levels of Python experience. Due to this, it's important to take care to keep the code understandable without a high level of Python-specific knowledge. Using basic structured programming constructs (i.e., <code>def</code>, <code>if</code>, <code>while</code>, etc.) and simple classes rather than heavy object-orientation or more esoteric functional programming tricks is recommended. If you need to create a complex class, method or functions, you may want to discuss it with other developers and the administrator first and then document the code thoroughly. </p> <h3><span id="Where_Are_the_Globally_Scoped_Variables_defined?"></span><span class="mw-headline" id="Where_Are_the_Globally_Scoped_Variables_defined.3F">Where Are the Globally Scoped Variables defined?</span></h3> <p>Almost all CGI scripts which comprise the ISFDB system have a <code>from isfdb import *</code> statement at the top of the script. Module <code>isfdb</code> defines many all-uppercase variables like <code>COPYRIGHT</code>, <code>EURO_SIGN</code>, offset values for tuples retrieved from the SQL database, etc. It also sets up <code>SESSION</code>, an object which contains session-specific information like the name of the directory that the current CGI script resides in. In addition, module <code>isfdb</code> executes <code>from localdefs import *</code>, which imports installation-specific global variables like <code>HTMLHOST</code> and <code>WIKILOC</code>. Upon import, all of these variable become available to the invoking CGI script. </p><p>ISFDB scripts which interact with the SQL database, i.e. the vast majority of them, import functions from SQLparsing. When the import occurs, the SQLparsing module creates a database connection and assigns it to the global variable <code>db</code>, which is then used by individual CGI scripts and other modules to interact with the database. SQLparsing also retrieves a list of supported languages and assigns it to the globally scoped variable <code>LANGUAGES</code>. </p> <h3><span class="mw-headline" id="Code_Format">Code Format</span></h3> <h4><span class="mw-headline" id="Indentation">Indentation</span></h4> <p>Older ISFDB modules tend to use tabs. Newer ISFDB modules tend to use 8 spaces. A few ISFDB modules use 4 spaces. Some modules use a mix of spaces and tabs, which can cause problems, especially if and when we migrate from Python 2 to Python 3. </p> <ul><li>For new development, use 8 spaces.</li> <li>When modifying existing modules which use either spaces OR tabs, use the current indentation method.</li> <li>When modifying existing modules which use a mix of spaces and tabs, change the module to use 8 spaces. This may require additional testing to ensure that nothing got broken.</li></ul> <h4><span class="mw-headline" id="Other_Standards">Other Standards</span></h4> <ul><li>When modifying existing code, use the naming conventions and other standards found within the module.</li> <li>For new development, use <a rel="nofollow" class="external text" href="http://www.python.org/dev/peps/pep-0008/">PEP 8: Style Guide for Python Code</a> unless it goes ISFDB-wide coding conventions.</li></ul> <h3><span class="mw-headline" id="How_to_Add_a_New_Cleanup_Report">How to Add a New Cleanup Report</span></h3> <p>ISFDB has three background jobs, not counting the backups: </p> <ul><li>Nightly job. It regenerates less computationally intensive <a rel="nofollow" class="external text" href="http://www.isfdb.org/cgi-bin/mod/cleanup.cgi?1">Cleanup Reports</a> and takes over 5 minutes to run.</li> <li>Weekly job. It regenerates all <a rel="nofollow" class="external text" href="http://www.isfdb.org/cgi-bin/stats-and-tops.cgi">Statistics and Top Lists</a> as well as <i>all</i> Cleanup Reports. It takes over 20 minutes to run.</li> <li>Monthly job. It regenerates cleanup reports which take a very long time to run. At this time it is only used to regenerate the "Suspected Duplicate Authors" report. The job is currently suspended because the algorithm doesn't scale well and it takes many days to complete.</li></ul> <p>If you want to add another cleanup report, use the following steps: </p> <ol><li>Develop a SQL query to find potentially problematic records. Your query should return only one column, which should contain the record ID of a suspicious record. Any subsequent columns will be ignored by the report generator. Note that you should only retrieve one record type (titles, pubs, series, etc) per report. If you need to return multiple record types, create one report per record type.</li> <li>Add a new report to the bottom of module <code>nightly/nightly_update.py</code>. Set the <code>query</code> variable to the body of the SQL statement that you created in the previous step. Invoke <code>standardReport(query, NNN)</code> where NNN is the report number of your report. To determine the value of NNN, take the last report number used and add 1. When this module is run by the nightly job, it will extract the specified record IDs and add them to the "cleanup" table in the database.</li> <li>In module <code>edit/cleanup_lib.py</code>, add the name of the new report to the dictionary <code>reports</code> in function <code>reportsDict</code>. Increment the last use key to get the key for your report -- it should be the same as the report number that you created in the previous step. In the same function, add this report number to the appropriate tuple of the <code>sections</code> list. For example, if you are developing a cleanup report that affects magazines, add the report number to the <code>Magazines</code> tuple. If the report is supposed to be accessed by editors without moderator privileges, add its number to the of the <code>non_moderator</code> tuple in the same function.</li> <li>In module <code>edit/cleanup_report.py</code>, create a new function called <code>functionNNN</code> where NNN is the report number describe in the last two steps. The function should take no arguments, e.g. <code>def function555()</code>. Define a SQL query that contains the same logic as the query describe in the first step except that it also limits the search to the records stored in the table "cleanup" for this report number. To do this, add the following logic to the <code>WHERE</code> clause of the SQL statement: <code>and TABLE_NAME.RECORD_ID=cleanup.record_id and cleanup.report_type=NNN and cleanup.resolved IS NULL</code>, where TABLE_NAME is the table name of the record that you are extracting, RECORD_ID is the name of the column of the record ID and NNN is the report number. Display the retrieved data using other reports as an example. Use function <code>PrintTableColumns</code> to print table columns. Use functions <code>PrintSeriesRecord</code>, <code>PrintPublicationRecord</code>, <code>PrintTitleRecord</code>, <code>PrintAuthorRecord</code>, <code>PrintPublisherRecord</code> and <code>PrintPubSeriesRecord</code> to print simple rows consisting of two columns: row number and a link to the problematic database record. These functions also support an optional third column for "Ignore this record" links. See the function definitions for the parameters that they take.</li></ol> <h3><span class="mw-headline" id="How_to_Add_a_new_Field_to_Title_records">How to Add a new Field to Title records</span></h3> <ol><li>Create a SQL script to add the new field to the titles tables</li> <li>Modify the <code>load</code> and <code>cgi2obj</code> methods of the <code>Title</code> class</li> <li>Add the new field to the Edit Title modules (<code>edit/edittitle.py</code>, <code>edit/submittitle.py</code>, <code>mod/ta_update.py</code>)</li> <li>Add the new field to the <code>DisplayTitleEdit</code> function in <code>biblio/viewers.py</code></li> <li>Add the new field to <code>biblio/title.py</code></li> <li>Consider whether the field needs to be displayed in the "Content" section of the "Publication" display page, similar to non-genre or graphic. If so, modify <code>biblio/pl.py</code></li> <li>Consider whether the field should appear on "Summary/Series" pages, similar to non-genre or graphic</li> <li>Consider whether the new field should be added to the "New Pub" data entry form, similar to non-genre or graphic</li> <li>Add mouse-over help in <code>edit/isfdblib.py</code>. If the field has also been added to "NewPub", make sure to add it to two places in <code>edit/isfdblib.py</code>, one for "Title Help" and one for "Pub Help".</li> <li>Account for the new field in the following module groups, including the data entry forms, the relevant viewers.py functions and the filers: <ul><li>Title Merge</li> <li>Title Unmerge</li> <li>Add Variant</li> <li>Variant Title</li></ul></li> <li>Consider adding the new field to the "Title" section of the "Advanced Search"</li></ol> <h3><span class="mw-headline" id="How_to_Add_a_New_External_ID_Type">How to Add a New External ID Type</span></h3> <ol><li>Add the requested External ID Type to the MySQL table <code>identifier_types</code>. For example, here is the command that added KBR as a new External ID Type: <ul><li><div class="mw-highlight mw-highlight-lang-mysql mw-content-ltr" dir="ltr"><pre><span></span><span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">identifier_types</span> <span class="p">(</span><span class="n">identifier_type_name</span><span class="p">,</span> <span class="n">identifier_type_full_name</span><span class="p">)</span> <span class="k">VALUES</span> <span class="p">(</span><span class="s1">'KBR'</span><span class="p">,</span> <span class="s1">'De Belgische Bibliografie/La Bibliographie de Belgique'</span><span class="p">);</span> </pre></div></li></ul></li> <li>If the new External ID Type links to one or more third party URL, add that URL (or URLs) to the MySQL table <code>identifier_sites</code>, one URL per command. Use "%s" for the part of the URL which will be replaced with the actual External ID at run time. Use the value of <code>identifier_type_id</code> generated by the previous command. For example, here is the command that added the URL of De Belgische Bibliografie: <ul><li><div class="mw-highlight mw-highlight-lang-mysql mw-content-ltr" dir="ltr"><pre><span></span><span class="k">INSERT</span> <span class="k">INTO</span> <span class="n">identifier_sites</span> <span class="p">(</span><span class="n">identifier_type_id</span><span class="p">,</span> <span class="n">site_position</span><span class="p">,</span> <span class="n">site_url</span><span class="p">)</span> <span class="k">VALUES</span> <span class="p">(</span><span class="mi">19</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="s1">'https://opac.kbr.be/Library/doc/SYRACUSE/%s/'</span><span class="p">);</span> </pre></div></li></ul></li> <li>If applicable, create a matching linking template using the <a rel="nofollow" class="external text" href="https://www.isfdb.org/cgi-bin/mod/bureaucrat.cgi?N">Bureaucrat-only</a> menu option "Add a New ISFDB Template", then add it to <a href="/wiki/index.php/Help:Using_Templates_and_HTML_in_Note_Fields" title="Help:Using Templates and HTML in Note Fields">Help:Using Templates and HTML in Note Fields</a>.</li></ol> <h3><span class="mw-headline" id="How_to_Add_a_New_Banner_Image">How to Add a New Banner Image</span></h3> <ol><li>Make sure that the new image file contains a valid JPG image</li> <li>Put a copy of the new image file in the <code>css</code> subdirectory</li> <li>Change the name of the new JPG file to <code>IsfdbBannerNN</code> where "NN" is 1 higher than the highest currently existing file name</li> <li>Add <code>IsfdbBannerNN.jpg</code> to <code>css/Makefile</code></li> <li>In <code>common/isfdb.py</code>, find the variable which contains the number of the last IsfdbBanner file and increment it by one to match NN</li></ol> <h3><span class="mw-headline" id="How_to_Add_a_New_Format_Code">How to Add a New Format Code</span></h3> <ol><li>Add the new format code to "self.formats" in class "_Db" in file common/isfdb.py</li> <li>Add the new format code and its description to "formats" in function "ISFDBPubFormat" in file common/library.py</li></ol> <h3><span id="How_to_Synchronize_ISFDB's_ISBN_ranges_with_the_International_ISBN_Agency"></span><span class="mw-headline" id="How_to_Synchronize_ISFDB.27s_ISBN_ranges_with_the_International_ISBN_Agency">How to Synchronize ISFDB's ISBN ranges with the International ISBN Agency</span></h3> <p>Currently this process requires the following steps on the development server: </p> <ol><li>Download the XML version of the most recent version of the official ranges from <a rel="nofollow" class="external free" href="https://www.isbn-international.org/range_file_generation">https://www.isbn-international.org/range_file_generation</a></li> <li>Copy the downloaded XML file to the "scripts" subdirectory</li> <li>Overwrite the old "ISBN_ranges.xml" file with the new XML file</li> <li>From the OS/cygwin prompt, switch to the "scrips" subdirectory and run the following command: "python import_ISBN_ranges.py"</li> <li>Pull up a random ISFDB publication record with an ISBN in one of the newly added ISBN ranges and confirm that the ISBN is correctly hyphenated. This will confirm that the structure of the International ISBN Agency's XML file hasn't changed and that the ISFDB import script is still working properly.</li></ol> <p>Once these steps have been completed, commit the new version of the "ISBN_ranges.xml" file to the SVN repository and install it on the production server as per the standard process. On the live server, switch to the "scrips" subdirectory and run the following command: "python import_ISBN_ranges.py". Pull up the ISFDB publication record that was used for testing purposes on the development server (see step 5 above) and confirm that the ISBN is correctly hyphenated. </p> <h3><span class="mw-headline" id="Duplicate_Functions_and_Duplicate_Filenames">Duplicate Functions and Duplicate Filenames</span></h3> <p>WARNING — There are duplicate file names and duplicate functions. The function <code>PrintNavBar</code> for instance, appears in <code>/biblio/common.py</code> (with 5 arguments) and in <code>/edit/isfdblib.py</code> (with 2 arguments) and again in <code>/mod/isfdblib.py</code> (with no arguments). Be sure to watch your directory of the file you are editing, and you cannot count on a function in one directory behaving the same when working in another directory. </p> <dl><dd>Indeed. When looking for <code>SQLwikiLinkExists</code> it turns out we have five of them, and rather too many <code>SQLparsing.py</code> files. We could do with some comparisons and centralisation, although this obviously has possibly far-ranging effects and would need lots of regression testing. <a href="/wiki/index.php/User:BLongley" title="User:BLongley">BLongley</a></dd></dl> <dl><dd><dl><dd>Files living in common are master files and are copied to the other parts of the tree during the build process. The good news is, CVS won't let you commit the others, as they don't actually exist in those directories in CVS. TortoiseCVS distinguishes them as local files with a different icon.... —<a href="/wiki/index.php/User:MartyD" title="User:MartyD">MartyD</a> 20:48, 14 June 2009 (UTC)</dd></dl></dd></dl> <dl><dd><dl><dd><dl><dd>This isn't a case of common files. This is duplicate file and function naming. <a href="/wiki/index.php/User:Kpulliam" title="User:Kpulliam">Kevin</a> 03:25, 15 June 2009 (UTC)</dd></dl></dd></dl></dd></dl> <dl><dd>I have begun the first step in the journey to fixing the <code>PrintNavBar</code> duplication problem. I've created a new <code>common/navbar.py</code> and made all of the other directories share it. We can slowly move NavBar things into it. —<a href="/wiki/index.php/User:MartyD" title="User:MartyD">MartyD</a> 21:14, 5 July 2009 (UTC)</dd></dl> <h1><span class="mw-headline" id="Related_Projects">Related Projects</span></h1> <ul><li><a href="/wiki/index.php/Solr_Powered_ISFDB" title="Solr Powered ISFDB">Solr Powered ISFDB</a></li> <li><a rel="nofollow" class="external text" href="https://pastebin.com/3dk8cC9R">Rough list of author countries from ISFDB database</a></li> <li><a rel="nofollow" class="external text" href="https://sf.ersatzculture.com/award-charts/">Charts showing SF&F award finalists and their rating counts on Goodreads</a> (award data from the ISFDB)</li></ul> <!-- NewPP limit report Cached time: 20250316022120 Cache expiry: 86400 Dynamic content: false Complications: [] CPU time usage: 0.038 seconds Real time usage: 0.174 seconds Preprocessor visited node count: 161/1000000 Post‐expand include size: 4918/2097152 bytes Template argument size: 4/2097152 bytes Highest expansion depth: 3/40 Expensive parser function count: 0/100 Unstrip recursion depth: 0/20 Unstrip post‐expand size: 2065/5000000 bytes --> <!-- Transclusion expansion time report (%,ms,calls,template) 100.00% 101.439 1 -total 41.25% 41.845 1 Template:Development-resources 14.16% 14.364 1 Template:Isfdb-general-header 14.09% 14.295 1 Template:SR --> <!-- Saved in parser cache with key isfdb-mw_:pcache:idhash:21127-0!canonical and timestamp 20250316022120 and revision id 709235 --> </div></div><div class="printfooter">Retrieved from "<a dir="ltr" href="https://isfdb.org/wiki/index.php?title=Development&oldid=709235">https://isfdb.org/wiki/index.php?title=Development&oldid=709235</a>"</div> <div id="catlinks" class="catlinks" data-mw="interface"><div id="mw-normal-catlinks" class="mw-normal-catlinks"><a href="/wiki/index.php/Special:Categories" title="Special:Categories">Categories</a>: <ul><li><a href="/wiki/index.php?title=Category:Pages_using_deprecated_source_tags&action=edit&redlink=1" class="new" title="Category:Pages using deprecated source tags (page does not exist)">Pages using deprecated source tags</a></li><li><a href="/wiki/index.php?title=Category:Pages_using_deprecated_enclose_attributes&action=edit&redlink=1" class="new" title="Category:Pages using deprecated enclose attributes (page does not exist)">Pages using deprecated enclose attributes</a></li></ul></div></div> </div> </div> <div id="mw-navigation"> <h2>Navigation menu</h2> <div id="mw-head"> <!-- Please do not use role attribute as CSS selector, it is deprecated. --> <nav id="p-personal" class="vector-menu" aria-labelledby="p-personal-label" role="navigation" > <h3 id="p-personal-label"> <span>Personal tools</span> </h3> <!-- Please do not use the .body class, it is deprecated. --> <div class="body vector-menu-content"> <!-- Please do not use the .menu class, it is deprecated. --> <ul class="vector-menu-content-list"><li id="pt-createaccount"><a href="/wiki/index.php?title=Special:CreateAccount&returnto=Development" title="You are encouraged to create an account and log in; however, it is not mandatory">Create account</a></li><li id="pt-login"><a href="/wiki/index.php?title=Special:UserLogin&returnto=Development" title="You are encouraged to log in; however, it is not mandatory [o]" accesskey="o">Log in</a></li></ul> </div> </nav> <div id="left-navigation"> <!-- Please do not use role attribute as CSS selector, it is deprecated. --> <nav id="p-namespaces" class="vector-menu vector-menu-tabs vectorTabs" aria-labelledby="p-namespaces-label" role="navigation" > <h3 id="p-namespaces-label"> <span>Namespaces</span> </h3> <!-- Please do not use the .body class, it is deprecated. --> <div class="body vector-menu-content"> <!-- Please do not use the .menu class, it is deprecated. --> <ul class="vector-menu-content-list"><li id="ca-nstab-main" class="selected"><a href="/wiki/index.php/Development" title="View the content page [c]" accesskey="c">Page</a></li><li id="ca-talk"><a href="/wiki/index.php/Talk:Development" rel="discussion" title="Discussion about the content page [t]" accesskey="t">Discussion</a></li></ul> </div> </nav> <!-- Please do not use role attribute as CSS selector, it is deprecated. --> <nav id="p-variants" class="vector-menu-empty emptyPortlet vector-menu vector-menu-dropdown vectorMenu" aria-labelledby="p-variants-label" role="navigation" > <input type="checkbox" class="vector-menu-checkbox vectorMenuCheckbox" aria-labelledby="p-variants-label" /> <h3 id="p-variants-label"> <span>Variants</span> </h3> <!-- Please do not use the .body class, it is deprecated. --> <div class="body vector-menu-content"> <!-- Please do not use the .menu class, it is deprecated. --> <ul class="menu vector-menu-content-list"></ul> </div> </nav> </div> <div id="right-navigation"> <!-- Please do not use role attribute as CSS selector, it is deprecated. --> <nav id="p-views" class="vector-menu vector-menu-tabs vectorTabs" aria-labelledby="p-views-label" role="navigation" > <h3 id="p-views-label"> <span>Views</span> </h3> <!-- Please do not use the .body class, it is deprecated. --> <div class="body vector-menu-content"> <!-- Please do not use the .menu class, it is deprecated. --> <ul class="vector-menu-content-list"><li id="ca-view" class="collapsible selected"><a href="/wiki/index.php/Development">Read</a></li><li id="ca-viewsource" class="collapsible"><a href="/wiki/index.php?title=Development&action=edit" title="This page is protected. You can view its source [e]" accesskey="e">View source</a></li><li id="ca-history" class="collapsible"><a href="/wiki/index.php?title=Development&action=history" title="Past revisions of this page [h]" accesskey="h">View history</a></li></ul> </div> </nav> <!-- Please do not use role attribute as CSS selector, it is deprecated. --> <nav id="p-cactions" class="vector-menu-empty emptyPortlet vector-menu vector-menu-dropdown vectorMenu" aria-labelledby="p-cactions-label" role="navigation" > <input type="checkbox" class="vector-menu-checkbox vectorMenuCheckbox" aria-labelledby="p-cactions-label" /> <h3 id="p-cactions-label"> <span>More</span> </h3> <!-- Please do not use the .body class, it is deprecated. --> <div class="body vector-menu-content"> <!-- Please do not use the .menu class, it is deprecated. --> <ul class="menu vector-menu-content-list"></ul> </div> </nav> <div id="p-search" role="search"> <h3 > <label for="searchInput">Search</label> </h3> <form action="/wiki/index.php" id="searchform"> <div id="simpleSearch"> <input type="search" name="search" placeholder="Search ISFDB" title="Search ISFDB [f]" accesskey="f" id="searchInput"/> <input type="hidden" name="title" value="Special:Search"> <input type="submit" name="fulltext" value="Search" title="Search the pages for this text" id="mw-searchButton" class="searchButton mw-fallbackSearchButton"/> <input type="submit" name="go" value="Go" title="Go to a page with this exact name if it exists" id="searchButton" class="searchButton"/> </div> </form> </div> </div> </div> <div id="mw-panel"> <div id="p-logo" role="banner"> <a title="Visit the main page" class="mw-wiki-logo" href="/wiki/index.php/Main_Page"></a> </div> <!-- Please do not use role attribute as CSS selector, it is deprecated. --> <nav id="p-navigation" class="vector-menu vector-menu-portal portal portal-first" aria-labelledby="p-navigation-label" role="navigation" > <h3 id="p-navigation-label"> <span>Navigation</span> </h3> <!-- Please do not use the .body class, it is deprecated. --> <div class="body vector-menu-content"> <!-- Please do not use the .menu class, it is deprecated. --> <ul class="vector-menu-content-list"><li id="n-ISFDB-Home-Page"><a href="https://www.isfdb.org/cgi-bin/index.cgi" rel="nofollow">ISFDB Home Page</a></li><li id="n-Main-Wiki-Page"><a href="/wiki/index.php/Main_Page">Main Wiki Page</a></li><li id="n-currentevents"><a href="/wiki/index.php/ISFDB:Current_events" title="Find background information on current events">Current events</a></li><li id="n-recentchanges"><a href="/wiki/index.php/Special:RecentChanges" title="A list of recent changes in the wiki [r]" accesskey="r">Recent changes</a></li><li id="n-Help"><a href="/wiki/index.php/Help:Contents">Help</a></li></ul> </div> </nav> <!-- Please do not use role attribute as CSS selector, it is deprecated. --> <nav id="p-Discussions" class="vector-menu vector-menu-portal portal" aria-labelledby="p-Discussions-label" role="navigation" > <h3 id="p-Discussions-label"> <span>Discussions</span> </h3> <!-- Please do not use the .body class, it is deprecated. --> <div class="body vector-menu-content"> <!-- Please do not use the .menu class, it is deprecated. --> <ul class="vector-menu-content-list"><li id="n-Help-Desk"><a href="/wiki/index.php/ISFDB:Help_desk">Help Desk</a></li><li id="n-Community-Portal"><a href="/wiki/index.php/ISFDB:Community_Portal">Community Portal</a></li><li id="n-Research-Assistance"><a href="/wiki/index.php/ISFDB:Research_Assistance">Research Assistance</a></li><li id="n-Rules-and-Standards"><a href="/wiki/index.php/Rules_and_standards_discussions">Rules and Standards</a></li><li id="n-Moderator-Noticeboard"><a href="/wiki/index.php/ISFDB:Moderator_noticeboard">Moderator Noticeboard</a></li></ul> </div> </nav> <!-- Please do not use role attribute as CSS selector, it is deprecated. --> <nav id="p-tb" class="vector-menu vector-menu-portal portal" aria-labelledby="p-tb-label" role="navigation" > <h3 id="p-tb-label"> <span>Tools</span> </h3> <!-- Please do not use the .body class, it is deprecated. --> <div class="body vector-menu-content"> <!-- Please do not use the .menu class, it is deprecated. --> <ul class="vector-menu-content-list"><li id="t-whatlinkshere"><a href="/wiki/index.php/Special:WhatLinksHere/Development" title="A list of all wiki pages that link here [j]" accesskey="j">What links here</a></li><li id="t-recentchangeslinked"><a href="/wiki/index.php/Special:RecentChangesLinked/Development" rel="nofollow" title="Recent changes in pages linked from this page [k]" accesskey="k">Related changes</a></li><li id="t-specialpages"><a href="/wiki/index.php/Special:SpecialPages" title="A list of all special pages [q]" accesskey="q">Special pages</a></li><li id="t-print"><a href="javascript:print();" rel="alternate" title="Printable version of this page [p]" accesskey="p">Printable version</a></li><li id="t-permalink"><a href="/wiki/index.php?title=Development&oldid=709235" title="Permanent link to this revision of the page">Permanent link</a></li><li id="t-info"><a href="/wiki/index.php?title=Development&action=info" title="More information about this page">Page information</a></li></ul> </div> </nav> </div> </div> <footer id="footer" class="mw-footer" role="contentinfo" > <ul id="footer-info" > <li id="footer-info-lastmod"> This page was last edited on 9 February 2025, at 07:52.</li> <li id="footer-info-copyright">Content is available under <a href="/wiki/index.php/Creative_Commons_License" title="Creative Commons License">Attribution</a> unless otherwise noted.</li> </ul> <ul id="footer-places" > <li id="footer-places-privacy"><a href="/wiki/index.php/ISFDB:Privacy_policy" title="ISFDB:Privacy policy">Privacy policy</a></li> <li id="footer-places-about"><a href="/wiki/index.php/ISFDB:About" class="mw-redirect" title="ISFDB:About">About ISFDB</a></li> <li id="footer-places-disclaimer"><a href="/wiki/index.php/ISFDB:General_disclaimer" title="ISFDB:General disclaimer">Disclaimers</a></li> </ul> <ul id="footer-icons" class="noprint"> <li id="footer-copyrightico"><a href="http://creativecommons.org/licenses/by/4.0/"><img src="https://i.creativecommons.org/l/by/4.0/88x31.png" alt="Attribution" width="88" height="31" loading="lazy"/></a></li> <li id="footer-poweredbyico"><a href="https://www.mediawiki.org/"><img src="/wiki/resources/assets/poweredby_mediawiki_88x31.png" alt="Powered by MediaWiki" srcset="/wiki/resources/assets/poweredby_mediawiki_132x47.png 1.5x, /wiki/resources/assets/poweredby_mediawiki_176x62.png 2x" width="88" height="31" loading="lazy"/></a></li> </ul> <div style="clear: both;"></div> </footer> <script>(RLQ=window.RLQ||[]).push(function(){mw.config.set({"wgPageParseReport":{"limitreport":{"cputime":"0.038","walltime":"0.174","ppvisitednodes":{"value":161,"limit":1000000},"postexpandincludesize":{"value":4918,"limit":2097152},"templateargumentsize":{"value":4,"limit":2097152},"expansiondepth":{"value":3,"limit":40},"expensivefunctioncount":{"value":0,"limit":100},"unstrip-depth":{"value":0,"limit":20},"unstrip-size":{"value":2065,"limit":5000000},"timingprofile":["100.00% 101.439 1 -total"," 41.25% 41.845 1 Template:Development-resources"," 14.16% 14.364 1 Template:Isfdb-general-header"," 14.09% 14.295 1 Template:SR"]},"cachereport":{"timestamp":"20250316022120","ttl":86400,"transientcontent":false}}});mw.config.set({"wgBackendResponseTime":56});});</script></body></html>