| Dec | JAN | Feb |
| 09 | ||
| 2020 | 2021 | 2022 |
COLLECTED BY
Formed in 2009, the Archive Team (not to be confused with the archive.org Archive-It Team) is a rogue archivist collective dedicated to saving copies of rapidly dying or deleted websites for the sake of history and digital heritage. The group is 100% composed of volunteers and interested parties, and has expanded into a large amount of related projects for saving online and digital history.
History is littered with hundreds of conflicts over the future of a community, group, location or business that were "resolved" when one of the parties stepped ahead and destroyed what was there. With the original point of contention destroyed, the debates would fall to the wayside. Archive Team believes that by duplicated condemned data, the conversation and debate can continue, as well as the richness and insight gained by keeping the materials. Our projects have ranged in size from a single volunteer downloading the data to a small-but-critical site, to over 100 volunteers stepping forward to acquire terabytes of user-created data to save for future generations.
The main site for Archive Team is at archiveteam.org and contains up to the date information on various projects, manifestos, plans and walkthroughs.
This collection contains the output of many Archive Team projects, both ongoing and completed. Thanks to the generous providing of disk space by the Internet Archive, multi-terabyte datasets can be made available, as well as in use by the Wayback Machine, providing a path back to lost websites and work.
Our collection has grown to the point of having sub-collections for the type of data we acquire. If you are seeking to browse the contents of these collections, the Wayback Machine is the best first stop. Otherwise, you are free to dig into the stacks to see what you may find.
The Archive Team Panic Downloads are full pulldowns of currently extant websites, meant to serve as emergency backups for needed sites that are in danger of closing, or which will be missed dearly if suddenly lost due to hard drive crashes or server failures.
Collection: Archive Team: The Github Hitrub
/** @jsx etch.dom */ const etch = require('etch') class MyComponent { // Required: Define an ordinary constructor to initialize your component. constructor (props, children) { // perform custom initialization here... // then call `etch.initialize`: etch.initialize(this) } // Required: The `render` method returns a virtual DOM tree representing the // current state of the component. Etch will call `render` to build and update // the component's associated DOM element. Babel is instructed to call the // `etch.dom` helper in compiled JSX expressions by the `@jsx` pragma above. render () { return <div></div> } // Required: Update the component with new properties and children. update (props, children) { // perform custom update logic here... // then call `etch.update`, which is async and returns a promise return etch.update(this) } // Optional: Destroy the component. Async/await syntax is pretty but optional. async destroy () { // call etch.destroy to remove the element and destroy child components await etch.destroy(this) // then perform custom teardown logic here... } }The component defined above could be used as follows:
// build a component instance in a standard way... let component = new MyComponent({foo: 1, bar: 2}) // use the component's associated DOM element however you wish... document.body.appendChild(component.element) // update the component as needed... await component.update({bar: 2}) // destroy the component when done... await component.destroy()Note that using an Etch component does not require a reference to the Etch library. Etch is an implementation detail, and from the outside the component is just an ordinary object with a simple interface and an
.element property. You can also take a more declarative approach by embedding Etch components directly within other Etch components, which we'll cover later in this document.
etch.initialize(component)
render method that returns a virtual DOM tree constructed with the etch.dom helper (Babel can be configured to compile JSX expressions to etch.dom calls). This function calls render and uses the result to build a DOM element, which it assigns to the .element property on your component object. etch.initialize also assigns any references (discussed later) to a .refs object on your component.
This function is typically called at the end of your component's constructor:
/** @jsx etch.dom */ const etch = require('etch') class MyComponent { constructor (properties) { this.properties = properties etch.initialize(this) } render () { return <div>{this.properties.greeting} World!</div> } } let component = new MyComponent({greeting: 'Hello'}) console.log(component.element.outerHTML) // ==> <div>Hello World!</div>
etch.update(component[, replaceNode])
.element property and updates the component's DOM element based on the current return value of the component's render method. If the return value of render specifies that the DOM element type has changed since the last render, Etch will switch out the previous DOM node for the new one unless replaceNodeisfalse.
etch.update is asynchronous, batching multiple DOM updates together in a single animation frame for efficiency. Even if it is called repeatedly with the same component in a given event-loop tick, it will only perform a single DOM update per component on the next animation frame. That means it is safe to call etch.update whenever your component's state changes, even if you're doing so redundantly. This function returns a promise that resolves when the DOM update has completed.
etch.update should be called whenever your component's state changes in a way that affects the results of render. For a basic component, you can implement an update method that updates your component's state and then requests a DOM update via etch.update. Expanding on the example from the previous section:
/** @jsx etch.dom */ const etch = require('etch') class MyComponent { constructor (properties) { this.properties = properties etch.initialize(this) } render () { return <div>{this.properties.greeting} World!</div> } update (newProperties) { if (this.properties.greeting !== newProperties.greeting) { this.properties.greeting = newProperties.greeting return etch.update(this) } else { return Promise.resolve() } } } // in an async function... let component = new MyComponent({greeting: 'Hello'}) console.log(component.element.outerHTML) // ==> <div>Hello World!</div> await component.update({greeting: 'Salutations'}) console.log(component.element.outerHTML) // ==> <div>Salutations World!</div>There is also a synchronous variant,
etch.updateSync, which performs the DOM update immediately. It doesn't skip redundant updates or batch together with other component updates, so you shouldn't really use it unless you have a clear reason.
writeAfterUpdate If you need to write to any part of the document as a result of updating your component, you should perform these writes in an optional writeAfterUpdate method defined on your component. Be warned: If you read from the DOM inside this method, it could potentially lead to layout thrashing by interleaving your reads with DOM writes associated with other components.
readAfterUpdate If you need to read any part of the document as a result of updating your component, you should perform these reads in an optional readAfterUpdate method defined on your component. You should avoid writing to the DOM in these methods, because writes could interleave with reads performed in readAfterUpdate hooks defined on other components. If you need to update the DOM as a result of your reads, store state on your component and request an additional update via etch.update.
These hooks exist to support DOM reads and writes in response to Etch updating your component's element. If you want your hook to run code based on changes to the component's logical state, you can make those calls directly or via other mechanisms. For example, if you simply want to call an external API when a property on your component changes, you should move that logic into the update method.
etch.destroy(component[, removeNode])
etch.destroy. This function will call destroy on any child components (child components are covered later in this document), and will additionally remove the component's DOM element from the document unless removeNodeisfalse. etch.destroy is also asynchronous so that it can combine the removal of DOM elements with other DOM updates, and it returns a promise that resolves when the component destruction process has completed.
etch.destroy is typically called in an async destroy method on the component:
class MyComponent { // other methods omitted for brevity... async destroy () { await etch.destroy(this) // perform component teardown... here we just log for example purposes let greeting = this.properties.greeting console.log(`Destroyed component with greeting ${greeting}`) } } // in an async function... let component = new MyComponent({greeting: 'Hello'}) document.body.appendChild(component.element) assert(component.element.parentElement) await component.destroy() assert(!component.element.parentElement)
render method, as follows:
/** @jsx etch.dom */ const etch = require('etch') class ChildComponent { constructor () { etch.initialize(this) } render () { return <h2>I am a child</h2> } } class ParentComponent { constructor () { etch.initialize(this) } render () { return ( <div> <h1>I am a parent</div> <ChildComponent /> </div> ) } }A constructor function can always take the place of a tag name in any Etch JSX expression. If the JSX expression has properties or children, these will be passed to the constructor function as the first and second argument, respectively.
/** @jsx etch.dom */ const etch = require('etch') class ChildComponent { constructor (properties, children) { this.properties = properties this.children = children etch.initialize(this) } render () { return ( <div> <h2>I am a {this.properties.adjective} child</h2> <h2>And these are *my* children:</h2> {this.children} </div> ) } } class ParentComponent { constructor () { etch.initialize(this) } render () { return ( <div> <h1>I am a parent</div> <ChildComponent adjective='good'> <div>Grandchild 1</div> <div>Grandchild 2</div> </ChildComponent> </div> ) } }If the properties or children change during an update of the parent component, Etch calls
update on the child component with the new values. Finally, if an update causes the child component to no longer appear in the DOM or the parent component itself is destroyed, Etch will call destroy on the child component if it is implemented.
.element property and an update method, it can be nested within an Etch virtual DOM tree. Your component can also implement destroy if you want to perform teardown logic when it is removed from the parent component.
This feature makes it easy to mix components written in different versions of Etch or wrap components written in other technologies for integration into an Etch component. You can even just use raw DOM APIs for simple or performance-critical components and use them straightforwardly within Etch.
key property to identify it. This improves performance by allowing Etch to determine whether a given element tree should be inserted as a new DOM node, or whether it corresponds to a node that already exists that needs to be updated.
ref property on a virtual DOM element as an instruction to wire a reference to the underlying DOM element or child component. These references are collected in a refs object that Etch assigns on your component.
class ParentComponent { constructor () { etch.initialize(this) } render () { return ( <div> <span ref='greetingSpan'>Hello</span> <ChildComponent ref='childComponent' /> </div> ) } } let component = new ParentComponent() component.refs.greetingSpan // This is a span DOM node component.refs.childComponent // This is a ChildComponent instanceNote that
ref properties on normal HTML elements create references to raw DOM nodes, while ref properties on child components create references to the constructed component object, which makes its DOM node available via its element property.
onproperty, which can be used to assign a hash of eventName: listenerFunction pairs:
class ComponentWithEvents { constructor () { etch.initialize(this) } render () { return <div on={{click: this.didClick, focus: this.didFocus}} /> } didClick (event) { console.log(event) // ==> MouseEvent {...} console.log(this) // ==> ComponentWithEvents {...} } didFocus (event) { console.log(event) // ==> FocusEvent {...} console.log(this) // ==> ComponentWithEvents {...} } }As you can see, the listener function's
this value is automatically bound to the parent component. You should rely on this auto-binding facility rather than using arrow functions or Function.bind to avoid complexity and extraneous closure allocations.
attributes property with a nested object. For example, aand bbelow will yield the equivalent DOM node.
const a = <div className='foo' /> const b = <div attributes={{class: 'foo'}} />This can be useful for custom attributes that don't map to DOM node properties.
update method.
class ControlledComponent { constructor (props) { this.props = props etch.initialize(this) } render () { // read from this.props here } update (props) { // you could avoid redundant updates by comparing this.props with props... this.props = props return etch.update(this) } }Compared to React, control is inverted. Instead of implementing
shouldComponentUpdate to control whether or not the framework updates your element, you always explicitly call etch.update when an update is needed.
render method's output is based on state managed within the component itself, call etch.update whenever this state is updated. You could store all state in a sub-object called state like React does, or you could just use instance variables.
class StatefulComponent { constructor () { this.counter = 0 etch.initialize(this) } render () { return ( <div> <span>{this.counter}</span> <button onclick={() => this.incrementCounter()}> Increment Counter </button> </div> ) } incrementCounter () { this.counter++ // since we updated state we use in render, call etch.update return etch.update(this) } }
setScheduler method that allows you to override the scheduler it uses to coordinate DOM writes. When using Etch inside a larger application, it may be important to coordinate Etch's DOM interactions with other libraries to avoid synchronous reflows.
For example, when using Etch in Atom, you should set the scheduler as follows:
etch.setScheduler(atom.views)Read comments in the scheduler assignment and default scheduler source code for more information on implementing your own scheduler.