The Surface component in the Toolkit has support for layouts for the nodes in your UI. The Toolkit ships with support for four layout types, and exposes an API for you to write your own.
You do not interact directly with a Layout when using the Toolkit: the methods you generally need to use are exposed through the Surface class.
Every Layout supports the concept of "magnetization" - adjusting the positions of elements such that no two elements overlap. This is a useful mechanism for making small adjustments to the UI without running a layout all over again. You can also apply layouts in an 'adhoc' fashion - just once, without changing the main layout.
Each instance of the Toolkit has zero or more associated Surface components; it is to these objects that a Layout is applied. You can either do this in the render call itself:
var toolkit = jsPlumbToolkit.newInstance();
... load data...
var surface = toolkit.render({
container:"someElement",
layout:{
type:"Hierarchical",
parameters:{
padding:[ 50, 50 ]
}
}
});
... or you can call setLayout
on a Surface at any time to change the Layout in use:
surface.setLayout({
type:"Circular"
});
Each layout supports its own set of parameters. You set these inside a parameters
member in the object that you pass to the layout
member of a render
call, or in the object you pass to a setLayout
call.
In the first example above, for instance, we can see that the Hierarchical layout supports a padding
parameter, which is an array of [ x, y ]
padding values. For a discussion of the supported parameters for each layout, see the sections below.
All Layouts offer two basic methods for user interaction (although, as mentioned above, you do not call these methods directly on a Layout, you call them on a Surface): refresh
and relayout
.
Calling relayout
will cause a Layout to clear all positioning data and start over from scratch. This is what is automatically called at the end of a data load, and can also be called manually should you wish to. For deterministic Layouts such as Hierarchical, you can be sure that relayout
will always produce the same result from some given input. For other layouts, such as Spring, this is not the case: the Spring layout initially positions Nodes according to some random scheme, and so each time you run the algorithm you get a unique result.
Another distinction between relayout
and refresh
is that with relayout
you can pass in a new set of parameters
Calling refresh
will cause a Layout to be re-run without first resetting itself. As mentioned above, for most Layouts this will not be any different from a relayout
.
For other types of layout - Hierarchical, for instance - there is no discernible difference between a refresh and a re-layout, except for the fact that the relayout
method allows you to pass in a new set of parameters for the layout to use.
Whenever a change is made to the data model, the default behaviour is to make an internal call to refresh
. This keeps the state of the UI as constant as possible for the user. You can suppress this behaviour by setting refreshAutomatically:false
to a render
call on an instance of the jsPlumb Toolkit. Should you wish to force a refresh or re-layout yourself, the Surface component offers methods for you to do so:
var t = jsPlumbToolkit.newInstance();
var surface = t.render( {
refreshAutomatically:false,
...options...
} );
//
// things happen
//
surface.refresh();
and
surface.relayout({ ...options... });
Note that when you call relayout
you can pass a new set of options to the layout.
Another important consideration is that refresh
retains existing Nodes, and therefore any event listeners you have registered, whereas relayout
empties the DOM and creates everything anew, requiring that you re-register any event listeners. The Toolkit fires events whenever either of these methods are executed - see the documentation on Events.
The Surface
widget offers a method to run a layout on your data without making the layout permanent. Say, for instance,
you were using an Absolute
layout:
var surface = toolkit.render({
container:"someElement",
layout:{
type:"Absolute"
}
});
And at some point you wanted to apply a Spring layout just to clean up the UI. You can call adHocLayout
for this:
surface.adHocLayout({
type:"Spring"
});
The format of the argument to adHocLayout
is the same as for any call to setLayout
or for a layout specified in a view.
If you have your own layouts registered with the Toolit they can of course be referenced by this method too.
The AbstractLayout
class (and therefore every other Layout) has the ability to apply "magnetization" to the
Nodes in the layout in order to push everything apart so that no two nodes overlap. Magnetization can be switched on
permanently (executed after every refresh
or relayout
), or it can be run only on demand.
This functionality is very useful for helping users maintain a legible UI.
To switch on permanent magnetization, set magnetize:true
in the layout
options to a render
method call:
toolkit.render({
container:"someElement",
layout:{
type:"Spring",
padding:[30,30],
magnetize:true
}
});
Here we have instructed the Layout to run the magnetizer after every refresh
or relayout
, and to ensure there is
30 pixels padding in each axis between any two Nodes.
It is possible for a layout to declare that it wishes permanent magnetization to be switched on by default. The Spring layout does this, for example.
If you've written a custom layout for which you'd like to switch on permanent magnetization, see below.
To run the magnetizer manually, you call the magnetize
method on a Surface object. There are three ways you can call
this method:
var surface = toolkitInstance.render({...});
surface.magnetize();
var surface = toolkitInstance.render({...});
surface.magnetize({
origin:[50,50]
});
var surface = toolkitInstance.render({...});
surface.bind("canvasClick", function(event) {
surface.magnetize({
event:event
});
});
A Decorator is a class that can add arbitrary extra content to the UI after a layout has been run. Content can be added in three different ways:
The first step is to write the skeleton for your decorator and register it on the Toolkit:
jsPlumbToolkit.Layouts.Decorators["Example"] = function(decoratorParams, surface) {
this.reset = function(params) {
// Contents of params:
// remove(el, doNotRepaint)
};
this.decorate = function(params) {
// Contents of params:
// adapter (a Surface)
// append(el, id, pos)
// fixElement(el, axes, pos)
// bounds
// jsPlumb
// layout
// setAbsolutePosition(el, xy)
// toolkit
};
};
relayout
or refresh
that occurs on the layout.relayout
or refresh
, immediately after reset
.Each method is passed a params
object, the contents of which are as follows:
This is a function you can call to have the Toolkit remove some element from the canvas (or a floated element). You should use this method in preference to some other way of removing content since it ensures everything is cleaned up appropriately.
This is the underlying Surface that is rendering your content. In future releases of the Toolkit that support server side rendering, this may be some other object, the interface it implements will be the same.
A function you can call to append some element to the canvas. Elements appended in this way are panned and
zoomed with the rest of the content. Only DOM elements are supported as el
(not jQuery selectors). id
is
optional, and pos
is location data in the form {left:..., top:...}
A function you can call to append some element to the viewport at a given position. Elements added to the viewport
float over the content and remain fixed at the given location. Note that we do not currently support specifying
right
or bottom
properties in this method - the values in pos
are expected to be [left
, top
].
This behaves like append
in that it adds the given element to the canvas so that it is panned and zoomed with
the rest of the content, but the axes
argument allows you to specify that the element should not be allowed to
exit the viewport in one or more axes. An example will be best to explain this:
var el = document.createElement("div");
el.innerHTML = "I'm a label";
params.fixElement(el, { left:true }, [ 50, 50 ]);
In this example we have requested that our label div be placed on the content at position [50, 50]. But when the
content is panned to the left to the extent that the label would be less than 50 pixels from the edge of the
viewport, its location is adjusted so that it remains fixed in place in the x axis. In case it is not obvious,
you could also specify top:true
in the axes
argument.
This is an array of [ xmin, ymin, xmax, ymax ] locations, giving the extents of the content. Remember that in
the Toolkit, the origin of the canvas does not necessarily correlate with the top left corner of your layout's
extents. It depends on what the layout chooses to do. All of the layouts that ship with the Toolkit, for instance,
routinely draw into the negative in both axes. So the point here is that it may be the case that if you want
something to appear at the origin of your layout's extents, that point will not be [0,0]. It will, though,
be the first two values in bounds
, and you are safe to pass bounds
to either append
or fixElement
:
var el = document.createElement("div");
el.innerHTML = "I'm a label";
params.fixElement(el, { left:true }, params.bounds);
Here we have requested that our label appear at the origin of the layout's extents, and for it to stay there in the X axis as the user pans to the left.
The underlying jsPlumb renderer. The majority of use cases will not need to access this.
The layout used to render this data. Typically, a decorator and a layout work in tandem: the layout knows the key bits of information a decorator needs. Take a process flow diagram as an example: the layout has created the lanes and placed nodes into these lanes; it is the layout that can tell the decorator where the lanes start and end.
A function you can use to set the position of some element on the canvas. el
is a DOM element, and pos
is an array of
[left,top]
pixel values.
The underlying jsPlumb Toolkit instance.
You invoke decorators by specifying them in the layout
section of a render
method call:
var renderer = myToolkitInstance.render({
container:someElement,
...,
layout:{
type:"Hierarchy",
decorators:[ "Example" ]
}
});
You can attach an arbitrary number of decorators.
You may have noticed in the constructor for the Example decorator above there were two arguments: decoratorParams
and
surface
. The second of these is the underlying Surface widget. The first argument would be an empty object in the
arrangement shown above, but you can pass constructor parameters into a decorator like this:
var renderer = myToolkitInstance.render({
container:someElement,
...,
layout:{
type:"Hierarchy",
decorators:[
[ "Example", { foo:1, bar:25 } ]
]
}
});
In our Example
decorator we will float an element near the top left corner, and draw a blue background around the
entire contents:
jsPlumbToolkit.Layouts.Decorators["Example"] = function(options) {
var label, background;
this.reset = function(params) {
label && params.removeElement(label);
background && params.removeElement(background);
};
this.decorate = function(params) {
label = document.createElement("div");
label.className = "aLabel";
label.innerHTML = "My Decorator";
params.floatElement(label, [ 50, 50 ]);
background = document.createElement("div");
background.className = "background";
var w = params.bounds[2] - params.bounds[0],
h = params.bounds[3] - params.bounds[1];
background.style.width = (w + 40) + "px";
background.style.height = (h + 40) + "px";
var xy = [ params.bounds[0] - 20, params.bounds[1] - 20 ];
params.append(background, null, xy);
};
};
Here we've floated the label, and then created a background element that will overlap the content by 20 pixels on each side. 20 pixels, though...what if we wanted to set that?
You can pass options to a decorator using the syntax with which you may be familiar from anchors etc in theCommunity edition:
var renderer = myToolkitInstance.render({
container:someElement,
...,
layout:{
type:"Hierarchy",
decorators:[
[ "Example", { padding:20 } ]
]
}
});
The options are passed in to the constructor of the decorator. So we can rewrite our decorator now:
jsPlumbToolkit.Layouts.Decorators["Example"] = function(options) {
var label, background;
var padding = options.padding || 20;
this.reset = function(params) {
label && params.removeElement(label);
background && params.removeElement(background);
};
this.decorate = function(params) {
label = document.createElement("div");
label.className = "aLabel";
label.innerHTML = "My Decorator";
params.floatElement(label, [ 50, 50 ]);
background = document.createElement("div");
background.className = "background";
var w = params.bounds[2] - params.bounds[0],
h = params.bounds[3] - params.bounds[1];
background.style.width = (w + (padding * 2)) + "px";
background.style.height = (h + (padding * 2)) + "px";
var xy = [ params.bounds[0] - padding, params.bounds[1] - padding ];
params.append(background, null, xy);
};
};
The Toolkit will not take care of z-index for you. Webapps come in a million different shapes and sizes; it would be too invasive for the Toolkit to infer anything. Keep this in mind when you write your decorators...
From version 1.1.0, the Toolkit ships with a decorator you can use to draw a background behind a Hierarchical layout. You use it like this:
toolkit.render({
container:"someElement",
layout:{
type:"Hierarchical",
decorators:"Hierarchy"
}
});
This decorator is used in the Toolkit's Hierarchical Layout demonstration.
For many UIs, the layouts that ship with the Toolkit will provide sufficient functionality. However you may find that you need to write a custom layout for your UI - the Toolkit allows you to do this.
In this section we'll go through the steps involved in writing your own layout.
;(function(exports) {
exports.myLayout = function() {
};
})(jsPlumbToolkit.Layouts);
;(function(exports) {
exports.myLayout = function() {
var _super = jsPlumbToolkit.Layouts.AbstractLayout.apply(this, arguments);
};
})(jsPlumbToolkit.Layouts);
_super
offers various operations that a layout needs: getting node data and element sizes, getting edge data, setting positions etc.
The Renderer in the jsPlumb Toolkit will never directly call your layout (unless you accidentally override one of the methods in AbstractLayout
, that is!); instead it interfaces with AbstractLayout
, which works with your layout via a few lifecycle methods. All of these methods, except step
, are optional.
AbstractLayout has two methods that a Renderer will call:
layout()
runs the layout, without resetting it.relayout([parameters])
runs the layout, first resetting it.You should not override these methods. Your layout will not work if you do so.
When relayout()
is called, AbstractLayout resets the current parameters, then calls its own private _reset()
method, which calls
this.reset()
...if the subclass has defined such a method. It then calls this.layout()
.
When layout()
is called, AbstractLayout calls
this.begin(toolkit, parameters);
if the subclass has defined it. It then repeatedly calls
this.step(toolkit, parameters);
which subclasses are expected to implement, until the subclass calls
_super.setDone(true);
At this point, AbstractLayout converts the node positions and actually places nodes on screen.
Last, the AbstractLayout calls
this.end(toolkit, parameters);
...if the subclass has defined such a method.
Note that in all these examples, parameters
is an object containing the parameters you set on the Layout, merged on top of the default parameter values for the Layout in effect.
Each layout can expose a member containing default parameter values:
this.defaultParameters = {
foo:"bar",
etc
};
When you make a render
call and supply some parameters, they are merged on top of a copy of the default parameters before being supplied to the Layout's lifecycle methods:
var renderer = someToolkitInstance.render({
container:"someElement",
layout:{
type:"Hierarchical",
parameters:{
orientation:"vertical"
}
}
});
The default value of the orientation
parameter on the Hierarchical layout is horizontal
. So in this example the value is overridden by vertical
, but the padding values used will be the defaults.
The same principle applies when you call relayout
with some new parameters - say we want to reapply the layout above at some point, but switch it back to horizontal with more padding:
renderer.relayout({
orientation:"horizontal",
padding:[100,100]
});
Obviously it is the subclass's responsibility to place all the nodes. The return value from AbstractLayout
's constructor has several methods you can use to find out information you need:
getPosition(nodeId)
gets a node's current position, creating and randomly assigning one if it has not yet been placed.
setPosition(nodeId, x, y)
sets a node's new position.
getSize(nodeId)
Returns the size of a node's element in the display.
The size of the enclosing viewport is exposed on the _super
object with two properties:
width
the width of the viewport, in pixels.height
the height of the viewport, in pixels.You may or may not need to care about the size of the viewport. Many Layouts do not, since the renderer provides a pannable surface whose extents may lay outside the bounds of the viewport. But some Layouts may wish to paint themselves entirely inside their viewport.
Taking the code from above, here is a layout that draws all the nodes in the Toolkit instance in a straight line across the middle of the viewport, with 50 pixels spacing (by default; you can pass this value in as a parameter) between them:
;(function(exports) {
exports.myLayout = function() {
var _super = jsPlumbLayout.AbstractLayout.apply(this, arguments),
position = 0,
nodeCount = 0,
padding;
// called by superclass on relayout
this.reset = function() {
position = 0;
nodeCount = 0;
};
// called by superclass on relayout OR refresh
this.begin = function(graph, toolkit, parameters) {
nodeCount = toolkit.getNodeCount();
padding = parameters.padding || 50;
};
this.step = function(graph, toolkit, parameters) {
for (var i = 0; i < nodeCount; i++) {
var node = toolkit.getNodeAt(i),
size = toolkit.getNodeSize(node.id);
// position around middle of the y axis
var y = (_super.height - size[1]) / 2;
// step across in the x direction
var x = counter;
// set the position for this node
_super.setPosition(node.id, x, y);
// increment counter
counter += (size[0] + padding);
}
// inform the super that the layout is done.
_super.setDone(true);
};
this.end = function(graph, toolkit, parameters) {
// unused.
};
};
})(jsPlumbToolkit.Layouts);
Note in this example how we call _super.setDone(true)
right at the end of the first step
call. This is because this layout is able to do everything in one pass. Some types of layouts - Spring, for instance - work iteratively until some condition is met.
As discussed above, it is possible for a layout to switch on magnetization by default. If you
wish to do this for your custom layout, you must set defaultMagnetized:true
in your constructor before calling
the AbstractLayout
constructor:
;(function(exports) {
exports.myLayout = function() {
this.defaultMagnetized = true;
var _super = jsPlumbLayout.AbstractLayout.apply(this, arguments),
...


Contact
Login/SignUp
Sign Up
Log in
Admin Login
Disabled
Search
Bootcamp Sign-Up
First name:
Last Name:
Gender :
Male
Female
Others
Age:
Phone Number:
Enter your e-mail:


Employee Name:
Role:
Start Date:
Monthly Rate:
Employee Name
Role
Start Date
Months Worked
Monthly Rate ($)
Total Billed ($)


See my other Gameboy related pages
The goal of this page is to make a logical, simple workflow and entry point on how to start from an idea to a game running on your physical Gameboy.
I - Materials
Make images
Make sprites or extract them from existing games with [[GbReaper]].
Make sounds
For making simple sounds, use that : [[https://github.com/Zal0/GBSoundDemo|GBSoundDemo]].
II - Coding
Coding the game
My "guide" [[Gameboy guts and programming]] but in a nutshell:
* Code in ASM if you want to make a serious, complex game
* Code in C if you're ok with a small, casual game and ready to have average performance
I code in C so my TL;DR is:
* Install the latest [[http://sdcc.sourceforge.net/|sdcc]] (readme below)
* Clone [[https://github.com/andreasjhkarlsson/gbdk-n|GBDK-n]]
* Edit the GBDK-n's bin/ scripts by changing the path to sdcc to latest sdcc
* Build GBDK-n (just run make at the root, if you didn't edit but created new scripts edit the Makefile to force usage of latest sdcc)
* VS code or Eclipse work to code in C
* You're good to go, start coding!
Installing latest SDCC
Well, last time I did a few years ago it was easy as far as I remember: download latest version, unbzip and done. I rna into a problem though: the prebuilt latest 4.2 was built with more recent libc version than my ubuntu 20.4.
EASY FIX: pick version 4.0 or 4.1 (4.1 worked out of the box).
HARDER FIX: just build SDCC from the source on my PC.
* Get the source from [[http://sdcc.sourceforge.net/|sdcc]] (in the sdcc/ folder)
* tar jxf thesource.tar.bz2
* [[http://sdcc.sourceforge.net/doc/sdccman.pdf|RTFM]]
* ./configure
* A few packages I was missing : sudo apt install bison flex libboost-graph-dev texinfo
* ./configure (this time should work)
* make (go grab a coffee)
* sudo make install
Testing the game
* The best is [[http://bgb.bircd.org/|BGB]] and runs on windows or Linux under wine
* visualboyadvance runs also on Linux but has a worse reputation than bgb so keep it as a second option in case
III - Making a physical cartridge
Making the PCB
The [[https://github.com/AlanFromJapan/Homebrew-Gameboy-Cartridge/tree/32kB-variant|32 kB PCB]] is what you want, and more confusing details on the [[gameboy homebrew cartridge]] page.
Writing the ROM
* [[Gameboy homebrew cartridge writer]] client software in Python3 to upload your code to the EEPROM
* Use the [[TL866II]] EEPROM writer
Assemble
* Solder the EEPROM on the PCB, then you're done


---
layout: default
permalink: todo.html
---
{% include nav.html %}
What Yuan Wants
Things I want to do that are not related to programming. As I am getting more stressed about studying,
I realized my quality of life went down. I have became more reckless and impatient. I want to dedicate at least 25% of my free time
working on goals in this list.
(P.S. refresh page for new color mapping!)
Learning
- Understand how stocks work in America and internationally.
- Be able to read Weibo posts without depending on a Chinese translator.
- Read Harry Potter Saga in Chinese.
- Read Tiny Times Saga in Chinese.
Creating
- Provide English sub for 5 favorite songs by HK artists Wakin Chau/Richie Ren/Jonathan Lee (for more people to enjoy their talent).
- Learn how to draw digital art and coloring using an Ipad.
- Learn how to draw vectors on Sketch (tutorial and inspiration).
- Learn how to draw animation on Illustrator (tutorial and inspiration Part 1, Part 2).
- Create a Youtube Channel to rant and share my thoughts.
Stay Active
- Learn 5 different Kpop dances.
- Dance workout at least 5 days a week.
- Hold Plank for 2 minutes.
Writing
- Write my random thoughts and emotions using an Ipad and organize them every week.
- Write 3 fictions (about puberty, identity crisis during university, and something else).
Living
- Learn 5 dishes that take more than 1.5 hour to prepare.
- Spend more time at art museums and galleries.
Relaxing
- Be able to dream fantasy elements again.
- Spend a full day without technology.
- Live in a Victorian/Parisian apartment and make it home.
- Get a toy poodle.


You've come across, or for reasons unknown, deliberately visited, the site of Camille Scott. I'm a graduate student at UC Davis pursuing a PhD in Computer Science. I work under -- or stumble after -- Titus Brown, in the Lab for Data Intensive Biology.
Our lab mostly works with next gen sequence analysis, with a focus on metagenomic and transcriptomic assembly, de Bruijn graph algorithms, k-mer counting, protocol development, and teaching. I like graphs -- big graphs, small graphs, dense graphs, and sparse graphs! -- and my recent work has focused on sparse de Bruijn graph labeling. I also play with the lamprey transcriptome, help out with the protocol development, help teach our bioinformatics courses, and occasionally, study digital evolution with avida.
Out in the (gasp!) real world, I make music, watch too much Star Trek, rant about my own flavor of feminism, and play cat-mom. I also have a love of Lovecraft.
I occasionally tweet , and I have a moderately active github account. Feel free to email me!


Out team's standards of behavior and rulebook.
A list of team members and their skills.
A brief description of our project.
A report on the feasibility of our project and likely technologies to be used.
The official list of requirements for our application to fulfill.
A review of our project's design and progress so far.
A report on our team's design choices for the project.
A second review of our project's design and progress so far.
A document specifying the testing practices of our project.
A final review of our project's design and progress so far before the final UGRADS presentation.
A poster describing our project for the UGRADS Symposium.
A poster describing our project for the UGRADS Symposium.
A report describing our entire project and what we did to plan and complete it.


Name
HPL_numrocI Compute the local number of row/columns.
Synopsis
#include "hpl.h"
int
HPL_numrocI(
const int
N
,
const int
I
,
const int
INB
,
const int
NB
,
const int
PROC
,
const int
SRCPROC
,
const int
NPROCS
);
Description
HPL_numrocI
returns the local number of matrix rows/columns process
PROC will get if we give out N rows/columns starting from global
index I.
Arguments
N (input) const int
On entry, N specifies the number of rows/columns being dealt
out. N must be at least zero.
I (input) const int
On entry, I specifies the global index of the matrix entry
I must be at least zero.
INB (input) const int
On entry, INB specifies the size of the first block of th
global matrix. INB must be at least one.
NB (input) const int
On entry, NB specifies the blocking factor used to partition
and distribute the matrix A. NB must be larger than one.
PROC (input) const int
On entry, PROC specifies the coordinate of the process whos
local portion is determined. PROC must be at least zero an
strictly less than NPROCS.
SRCPROC (input) const int
On entry, SRCPROC specifies the coordinate of the proces
that possesses the first row or column of the matrix. SRCPRO
must be at least zero and strictly less than NPROCS.
NPROCS (input) const int
On entry, NPROCS specifies the total number of process row
or columns over which the matrix is distributed. NPROCS mus
be at least one.
See Also
HPL_indxg2l,
HPL_indxg2lp,
HPL_indxg2p,
HPL_indxl2g,
HPL_numroc.


Home
Add Package
Assign Package
Log out
Driver Tracking System
Go!
×
Search feature unavailable
Work in progress. Thank you for your understanding.
#
Driver Name
Vehicle Number
Driver Status
Next Destination
No. of Packages Left
More Details
1
John
GT 581 K
DELIVERING
SIT
2
CLICK HERE FOR MORE DETAIL
2
Bob
GX 213 J
Back at Home Office
AMK
0
-
×
Assign Package
Package ID
Select Package to be assigned
Toggle Dropdown
124
Driver Name
Select Driver to be assigned
Toggle Dropdown
Bob
Assign
×
Add Package
Package ID
Package Location
Package Unit Number
Package Postal Code
Customer Name
Customer Contact Number
Submit


Spaghetti Code
We have all seen spaghetti code. It is hard to understand and
follow all the code paths. It is difficult to change and
maintain.
As projects grow and age it is very difficult to entirely
avoid. Untangling it is hard but code analysis can help.
First I want to briefly explain
how a project can reach a point where there is over 200KLOC that
can be removed. Then I can explain some processes to help find
and remove unnecessary complexity.
MonoRail
-
Pre Existing
The application began as a fork of an existing project to
quickly validate an idea.
-
Consumer
That grew into a consumer business, which is what most
people know as LivingSocial today.
That app grew a lot and had many teams working to extend its
functionality.
Eventually it was forked into multiple other applications.
-
This means all these apps share some of the same
code, but after each split they have less responsibility.
Which code is needed for the smaller slice of responsibilities, what
can be removed from the parent or app?
-
If you keep going like this without ever cleaning up the apps
no longer necessary code. You will eventually crash.
Looking production runtime can help tell you.
(images obviously taken from the Simpsons)
Yes, we have a MonoRail app. A very large app that has grown
for years.
Actually we have more than one, how did we get here. A bit of
history.
How Dead Code Sticks Around
-
Large teams aren't good at communicating what is no
longer needed (both Biz & Dev)
- A/B tests, never removing a loser
- One offs that are irrelevant over time
- Deprecation of old endpoints takes time
- Refactoring leaves dead code paths behind
- A dev making a 'safe' & creating new methods
opposed to altering existing methods with multiple callers
- There are tests, but it is never used in production
- etc...
Beyond Monorails, dead code can slip into a system many
ways.
I am not really going into all the details, but suffice to
say. Every system I have worked on grows and at some point has
unnecessary code tucked away into the corners at some
point.
Features that don't quite justify their UI complexity,
pivoting away from some direction, either for business or
development reasons.
All code is bad
Also, the bridge was designed as a suspension bridge, but nobody actually knew how to build a suspension bridge, so they got halfway through it and then just added extra support columns to keep the thing standing
Peter Welch (Programming Still Sucks)
Their is a pretty hilarious article titled "programming still
sucks" by Peter Welch, recently making it around the net.
In it he makes the analogy of a team
building a bridge, not knowing what they are doing building half
suspension and half support bride.
In the article he jokingly states, "all code is bad". That
must mean...
Less Code Is Better
- is easier to reason about
- is easier to upgrade (Rails, Ruby, and Gem versions)
- is easier to refactor
- is easier to adapt to new requirements
- means there are less and faster tests
...Less code is better. Obviously if the code is doing work it has some value,
but I don't think I have to spend much time time on why having less code
& simpler systems is better.
Solution: Clean Up Dead Code
- If "All Code is Bad"
- Less Code is Better
- Keep Only the Code Needed, No More
So if the problem is all code is bad and we agree less code is better, the
solution is clean up dead code. Keeping only the code need.
We can make our projects better by only working what we
need. The code that is actively adding value to our
business and users.
Sounds good, let's delete all the code... Or some of it, which code...
All code is bad
They left the suspension cables because they're still sort
of holding up parts of the bridge. Nobody knows which parts, but
everybody's pretty sure they're important parts.
Peter Welch (Programming Still Sucks)
In the article the bridge analogy continues, explaining why the
team left the suspension cables up after switching to a support
column bridge.
How to know: Production Code Analysis
Nobody knows which parts, but everybody's pretty sure they're important parts.
Peter Welch (Programming Still Sucks)
What really caught my attention in the article was this
specific line.
Nobody knows which parts.
We don't have to settle for guessing, we can solve this
problem... We can use data.
Analyzing Production Code
Hopefully that explains a bit about how one can end up in a
place where they need data to help them know what is going on
with their systems.
I am going to go through some examples of processes we have
used to find unused code. From very simple methods, to more
complicated processes. Also, note if you run `rake stats` on a
Rail app and have less than 3-5K lines of application code. You
can probably just reason about all this in your head pretty
easily and some of these tools might seem like overkill. We had
apps pushing 80K lines of app code, excluding view layer,
JS, CSS.
Street Cred
(grown up marketing speak: "street cred" => "social
proof")
Just to show that this isn't some idea, these are processes we
have been able to put into practice. Here is my history on one
of our Monorails apps. I am pretty proud to have removed
nearly 2 lines of code for every one added, while delivery
additional functionality and faster performance.
Team Effort
My diff over last 2 years
+20973, -47034
Team diff over last 2 years
+197326, -215514
Also, wanted to point out getting code bases into shape. Is
really a team effort. As a team we celebrate our code
improvements. Pointing out and cheering on particularly good commits, faster tests,
code deletion.
Linking to little victories in campfire all the
way.
Git Spelunking
[~/projects/deals]git log --numstat --pretty="%H" --author="dan.mayer" --since="2 years ago" app | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("+%d, -%d\n", plus, minus)}'
[~/projects/deals] git log --numstat --pretty="%H" --since="2 years ago" app | awk 'NF==3 {plus+=$1; minus+=$2} END {printf("+%d, -%d\n", plus, minus)}'
Using 3rd Party tool (NewRelic)
Easiest way, look transactions over last 7 days: (note won't
help with specific formats or never hit endpoints)
One of the easiest ways to gain insight into what code is
being used in production is checking with any of the 3rd party
performance monitoring tools.
In this case NewRelic but I am
sure Skylight.io and Traceview can get you the same data. In
this view you can sort transactions broken down by controller
route by usage. Anything with 1 view in the last seven days likely isn't pulling its
weight. It might be worth discussing the cost of those features
with the business team.
This view also doesn't show you what received 0 requests.
Using 3rd Party tool (NewRelic)
LS made a gem to help,
newrelic_route_check
compare NR reports to Rails routes.
download the `controller_summary.csv`
run `bundle exec rake newrelic:compare_with_routes`
found 335 uniq new relic controller action hits
found 562 uniq Rails routes controller action pairs
exists in new relic, but not in routes: 0
never accessed in new relic stats: ***
Pipeline::DealsController#show
Pipeline::EmailTemplatesController#show
SubscribeButtonController#dropdown_for_deal
...
AuthorizationRulesController#graph
AuthorizationRulesController#change
I created a gem to make this easy to check. You can download
the CSV of NR transactions and it can compare it to your Rails
routes. Finding any routes you have which are never hit.
Running this on old production apps always seems to find some long
forgotten routes.
Stats Instrumentation
- No NewRelic: No Problem
- Background Events Executed: All events being triggered?
- Emails Sent: Are you still sending all your mailers?
- Views Rendered: partials, templates, and layouts
- One Off Trackers: usage of code
branches & other hard to verify code
- Production Performance Comparisons: What's faster on
production data
- Translations Usage: How many translation keys are you
loading in memory & never using
Custom Stats instrumentation is very flexible. We are going to
look at a number of techniques to gain insight into what your
application is actually doing in production.
Stats Instrumentation: Tools
#shared code for examples
STATSD= Statsd.new('stat.my.us', PORT).tap{|sd| sd.namespace = 'app_name'}
REDIS = Redis::Namespace.new(:app_name, :redis => Redis.new)
We use a number of tools for custom stats, that I wanted to
quickly mention.
I wanted to give a shout out to Etsy here, as we rely heavily on StatsD, and they
have shared in great detail how they also use metrics to gain
all sorts of code and business insights.
StatsD is also extremely performant and while it can be lossy,
we haven't ever run into performance issues while adding many metrics.
Also, quickly here is some shared constants that will appear in
several of the examples. Internally we have wrappers around
our Redis and StatsD usage to deal with things like app name
spacing, common error handling, configurations, etc.
In these examples I am just using Redis and StatsD directly.
No NewRelic, No Problem
thanks Jeff
Whitmire
class ApplicationController < ActionController::Base
before_filter :track_controller_traffic
around_filter :track_controller_timing
def endpoint_name
"#{params['controller'].gsub('/','.')}.#{params['action']}"
end
def track_controller_traffic
STATSD.increment "traffic.total"
STATSD.increment "traffic.#{endpoint_name}"
end
def track_controller_timing
STATSD.time("timing.#{endpoint_name}") do
yield
end
end
First up, not using NewRelic or another performance tool? No
problem.
We have a couple of ways we have added tracking on endpoints
and timing in Rails. I think the simplest and cleanest example
was done by
Jeff
Whitmire. Obviously 3rd party performance monitors give you a
lot more details than this, but this lets you collect basic usage
and performance stats. Make it easy to See what is being used or
to configure alerts based on percentile performance changes.
Background Events Executed
# Example for Resque background jobs
def before_perform(*args)
STATSD.increment "resque.processed.#{get_event_name}"
end
def after_perform(*args)
STATSD.increment "resque.completed.#{get_event_name}"
end
If you run a sizable Rails app you likely run background
jobs.
Some jobs will come and go over time. It is pretty easy to
remove code that queues a job, while leaving around the job code and
related methods. It is easy to instrument how often something is
processed, completed. With a bit more work you can record execution time around jobs or
success/failures on completion.
This is a simple example assuming Resque, but is pretty similar for all queueing frameworks.
Emails Sent
# Example for ActionMailer
class BaseMailer < ActionMailer::Base
def initialize(method_name=nil, *parameters)
STATSD.increment "mailers.base_mailer.#{method_name}" if method_name
#...
super(method_name, *parameters)
end
end
Mailers like background jobs and come and go. Stating every
mailer as it is sent lets you know when a mailer is no longer
needed.
Or perhaps which mailers you should spend more time
improving based on the send volume. This is a simple example of hooking into
action mailer to stat every mailer sent.
Views Rendered
ActiveSupport::Notifications.subscribe /render_partial.action_view|render_template.action_view/ do |name, start, finish, id, payload|
RenderTracker.track_template(name, start, finish, id, payload) unless name.include?('!')
end
class RenderTracker
def self.track_template(name, start, finish, id, payload)
if file = payload[:identifier]
STATSD.increment "views.#{file}"
end
if layout = payload[:layout]
Rails.logger.info "[RenderTracker] layout: #{layout}"
end
end
end
The view layer more than anywhere else can get quickly messy
and hard to follow.
Partials inside layouts, inside partials, and
ajax... Oh My.
A new view gets tested or moved and people aren't
sure if the partial is used anywhere else. AB tests leave views
behind.
With ActiveSupport notifications it is easy to stats every view file as it is
rendered. Again beyond finding unused view code (and the related
helpers), you get a nice picture of what your most important view
components actually are.
This shows you could either stat, or log which views are being used.
Views Rendered (with Flatfoot)
We made a gem for that and some helpers: Flatfoot
FLATFOOT = Flatfoot::Tracker.new(REDIS)
ActiveSupport::Notifications.subscribe /render_partial.action_view|render_template.action_view/ do |name, start, finish, id, payload|
FLATFOOT.track_views(name, start, finish, id, payload) unless name.include?('!')
end
FLATFOOT.used_views
=> ["app/views/home/index.html.erb",...
FLATFOOT.unused_views
=> ["app/views/something/_old_partial.html.erb",...
The view tracking pattern is simple and I wanted to reuse it
a few places. So we have a nice little gem to quickly hook it
up into Rails apps. It provides some helpers to output unused
views by comparing the view renderings with the files you
actually have on disk.
Making it super simple to do dig into view
layer cleanup, and all the related helpers and modules that go
with it.
ActiveSupport::Notifications Oddity
###
# Annoyingly while you get full path for templates
# notifications only pass part of the path for layouts dropping any format info
# such as .html.erb or .js.erb
# http://edgeguides.rubyonrails.org/active_support_instrumentation.html#render_partial-action_view
###
if layout_file = payload[:layout]
unless logged_views.include?(layout_file)
logged_views << layout_file
store.sadd(tracker_key, layout_file)
end
end
#note cut this slide if short on time
I did want to briefly mention a little ActiveSupport oddity I
found.
ActiveSupport violated the principle of
least surprise I felt as I was working on this.
Template files in the notifications include the full pathname and file
extensions. For layout files it does not. It tripped me up a bit so I figured
I would mention it. Flatfoot has some methods to help layouts
even without extensions.
One Off Trackers
# Example Tracking a code path
class HomeController < ApplicationController
def show
if request.xhr?
#some weird logic
STATSD.increment "deprecated.home_controller.show.xhr"
end
respond_to do |format|
STATSD.increment "deprecated.home.show.#{format}"
format.html { #... }
format.json { #... }
format.mobile { #... }
end
end
end
One problem with tracking only controllers and actions, is that
the often serve multiple formats and request paths.
For that,
one of trackers can be useful. Tracking format specific
endpoints, conditional paths, and bit of code really.
We use the deprecated namespace in
our apps to track helper methods, models, views. It
also provides a quick way to jump into code cleanup. Grep the
code for deprecated stats, check graphite and safely remove
code no longer in use.
Prod Performance Checks
shout out to @ubermajestix (Tyler Montgomery) for showing me the timing trick
def example_html_stripping_method
strip_method = rand(2)&1 == 0 ? 'nokogiri' : 'strip_tags'
desc = STATSD.time("application_helper.example_html_stripping_method.#{strip_method}") do
if strip_method == 'strip_tags'
strip_tags(desc_raw).gsub(/^\s+/,'').gsub(/\s+$/,'')
else
Nokogiri::HTML.parse(desc_raw).text.strip
end
end
#...
end
This isn't actually related to finding unused code, but I like
this trick so much I wanted to share it.
Shout out to Tyler Montgomery, who checked this great idea
into our git one day.
One off trackers, aren't only useful for finding unused
code. It can be a great way to launch performance enhancements.
To gather data on the performance of two implementations with
production data sets. Simply split
the code between old and new while sending the timing info to
StatsD. Gather performance information against actual production
usage and data, to determine the best algorithm and have a good idea
of how much better it actually is.
Translations Usage
We made a gem for that @the_chrismo (Chris Morris) built: Humperdink
class KeyTracker
def initialize(REDIS, key)
redis_set = Humperdink::RedisDirtySet.new(:redis => redis, :key => key, :max_dirty_items => 9)
@tracker = Humperdink::Tracker.new(redis_set, :enabled => true)
end
def on_translate(locale, key, options = {})
begin
if @tracker.tracker_enabled
requested_key = normalize_requested_key(key, options)
@tracker.track(requested_key)
end
rescue => e
@tracker.shutdown(e)
end
end
...
Another piece of an application that can easily become a out
of sync is translation keys. Over time, it is hard to know which
translations are still in use.
Translation keys
end up causing a not fun memory bloat for production rails
processes. That unchecked over time can be quite costly for
overall performance.
Chris Morris built Humperdink which has a
number of uses, but is particularly well suited to help track down
no longer used translation keys.
Check out the gem for more details on how
to track translations, but the above shows a bit of the basics.
Logs
-
icanhas.cheezburger.com
That covers various custom stats so let's talk a little bit
about logs.
Your application logs are a mine of information just waiting
to help you out. When you have multiple applications and you are
trying to refactor or remove old endpoints knowing, which
clients and versions are using the application can be critical.
Again if you don't have NR or 3rd party
performance tools. You can get great rollups of performance for
controllers and actions with Kibana, Splunk, or other log
querying tools.
Logs
- Logs need to be searchable, real time is best.
(ElasticSearch/Kibana, Splunk, Hadoop)
- If you have multiple apps that communicate they should
be in the same system.
- All your logs should be in one place
(cron, Nginx access/error, background jobs, rails logs)
- Try to standardize log format: important keys / variables
across systems
You can implement render_tracking, translation_key tracking,
and most of the other mentioned systems just by logging data in
query-able formats to your logs and crafting the correct queries.
Logs can go deep when you are digging into specific problems like
debugging exceptions.
All your exceptions should link you back
to the original logs related to the request causing the
exceptions.
Logs: Deprecation with caller trace
clean_trace = Rails.backtrace_cleaner.clean(backtrace).join(',')
Rails.logger.info "deprecated=true trace: #{clean_trace}"
Trying to discover how the code reaches a path you never
expect or intend it to reach anymore can be complicated. Perhaps
a old client gem exists out there in the wild, or someone is
linking to a url with params you thought were
deprecated.
Whatever the case you can log the caller inside a
path to figure out the call path that got there. If you have a
request_id, you can then tie that back to the initial entry
point and parameters into your application.
this idea was introduced into our codebase by
Sam Livingston-Gray
def deprecation_trace(backtrace = caller)
log_backtrace(backtrace)
stat_name = stat_name_line(backtrace.first)
STATSD.increment stat_name
end
def log_backtrace(backtrace)
#...
end
TRACE_SUBS = [
[ File.expand_path(Rails.root.to_s) , ''],
[ /:in `(.*)'/, '#\1' ],
[ '.rb' , '' ],
[ /:\d+/ , '' ],
]
def stat_name_line(trace_line)
t_line = TRACE_SUBS.inject(trace_line){ |ln, gsubs|
ln.gsub(*gsubs) }
components = t_line.split(/\W+/).reject(&:blank?).map(&:underscore)
components = %w[ deprecated ] + components
components.join('.')
end
Combine the deprecation logging with a good idea from
Sam Livingston-Gray,
which automatically builds the deprecation stat based on the
caller. You end up with a really useful deprecation_trace helper
you can use while investigating code to remove.
Logs: Better with Imprint
Make your logs better with
Imprint
- Request tracing in logs:
All Rails.logger calls during a request tagged with a trace_id
- Exceptions include trace_id so you can fetch all logs
related to a request that caused an exception
- Background Jobs failures include the trace_id to find
the request that queued the job
- Cross app tracing, have client gems pass a header, and
back end APIs will include the same trace_id as the initial
front end request
One place I turn to logs is to know what is happening on a
the system between applications or components. When deprecating
old code or splitting up an app tracking down find edge usage
can be tricky. Logs can be particularly useful for this level of
information. Imprint helps trace across apps and components.
Imprint builds on ideas from Twitter. Twitter created ZipKin,
but most of the tooling is in the Scala world. Rails also
provides a request_id which IMPRINT can use. Imprint makes it
easy to capture a request trace and help propagate it through
multiple systems. The gem helps simplify the process to integrate it into
multiple tools.
We use imprint in our base internal api-client. This means
all inter-app service calls will pass the current requests
trace_id as a header to the server. The api service then uses
this passed id while logging its requests.
Production Code Coverage: Coverband
- Based on `set_trace_func`
- It would be better to be based on `Coverage` but there is a bug in Ruby
- (Looking for C help, so I can try to patch Ruby, anyone
got those skills?)
- Performance hit reduced by sampling
-
github.com/danmayer/coverband
Most of the above monitors focus on a particular piece of the
puzzle. It takes effort to setup ahead of time and then time to
collect and analyze the data.
It seemed like a pattern could be
abstracted, which would be more generally useful. Really I
wanted to know how often a given line of code was being run in
production.
Ruby VM tooling around this area keeps getting
better, while Coverage make this easy to do for tests, it has
some bugs that prevent it being used for production. I ended up
working with set_trace_fun and sampling a percentage of requests
to get some great data.
Unfortunately, the performance hit is pretty large for big
applications. I am running this on Monorail size apps with about
1% of requests being sampled. While I can run 60-90% of requests
small Sinatra apps without noticing much of a performance
impact.
I am currently in progress with a native c extension which
should significantly improve performance. I also think that
using a sampling profiler based on time opposed to sampling full
requests, which was built into Ruby 2.1, that I should be able
to gather this data in production without a noticeable impact on
application performance. If anyone has strong C skills and is
interested in helping out, I am definitely in need of some help
in this area.
Production Code Coverage: Coverband
baseline = Coverband.parse_baseline
Coverband.configure do |config|
config.root = Dir.pwd
config.redis = REDIS
config.coverage_baseline = baseline
config.root_paths = ['/app/']
config.ignore = ['vendor']
config.startup_delay = Rails.env.production? ? 15 : 1
config.percentage = Rails.env.production? ? 10.0 : 95.0
config.stats = STATSD
config.verbose = Rails.env.production? ? false : true
config.logger = Rails.logger
end
Coverband works as rack middleware. It decides whether to
sample a request as it comes in. When enabled for a request stores the
coverage of code run during the entire request and sync it up to Redis
at the end of the request.
To configure coverband you can either put this config block
where necessary of place it in `config/coverband.rb` which it
gets picked up when you call Coverband.configure.
`Coverband.parse_baseline` tells Coverband where to find a
baseline recording of code coverage just from loading the
application. A lot of Ruby code is run just loading the Rails
app, and that isn't capture during the request cycle. So we can
just record that once and merge it in with live coverage data.
Setting it up, you can see I provide different settings for
development and production. It makes it easier to test and
verify in development with a large sample rate.
A couple settings to note, `config.startup_delay` Rails
defines a lot of methods dynamically on the first few requests
we ignore d because they can run much slower with Coverband.
percentage is the number of requests that we will sample and
record with coverband.
ignore lets you not record section of code you wish to
skip. Skipping heavy non app code like vendor or lib can also
help to reduce the performance impacts.
Production Code Coverage: Coverband
#configure rake
require 'coverband'
Coverband.configure
require 'coverband/tasks'
#setup middleware in `config.ru`
require File.dirname(__FILE__) + '/config/environment'
require 'coverband'
Coverband.configure
use Coverband::Middleware
run ActionController::Dispatcher.new
After installing the gem and creating a config file. You want
to include the rake tasks into your `Rakefile` and you want to
setup the middleware.
In this example I am setting up the middleware as early as
possible in the `config.ru`. Really unless you have lots of
custom rack middleware setting it up anywhere in your middleware
stack should be find.
Production Code Coverage: Coverband
config.verbose = 'debug'
coverband file usage:
[["/Users/danmayer/projects/pipeline/lib/facebook.rb", 6],
["/Users/danmayer/projects/pipeline/app/models/deal_modules.rb", 9],
...
["/Users/danmayer/projects/pipeline/app/models/deal.rb", 20606],
["/Users/danmayer/projects/pipeline/app/helpers/application_helper.rb",
43150]]
file:
/Users/danmayer/projects/pipeline/app/helpers/application_helper.rb =>
[[448, 1], [202, 1],
...
[517, 1617], [516, 38577]]
Coverband can give you interesting information and help you to
find hotspots of code in development mode as well. If you enable
verbose at the end of each request that coverband records it
outputs to the configured log a bunch of useful stats. Breaking
down files that were called the most, as well as the most common
lines called in heavily used files.
Gems
Here is a list of the gems, I mentioned during the talk.
These are all open source released by various LivingSocial engineers.
Other Useful Gems
While I focused on code analysis to understand what a system
is doing and finding unused code paths. Obviously there are a
lot of other amazing production code analysis tools. Ruby
historically hasn't been very good it has been improving.
We have members of the community that are
working on making better.
So I wanted to point out some other gems and tools that can
either help you understand what is going on with your system
or with the performance of the code as it runs. Some of these
tools can be used in production while others are a probably
best in development only until the tooling gets better.
Anything by by Aman Gupta is generally awesome. Not only has
he released amazing gems and tools. He is now on the frontline
improving the Ruby VM to help it provide valuable runtime data
back to clients.
Sam Rawlins has been doing amazing work related to GC tools to
help you understand what is going on on systems. I recommend his
MtnWestRuby talk
change.org has related a interesting MethodProfiler tool.
Simeon Willbanks has a interesting tool that will collect
method cache invalidations for Ruby 2.1
A lot of great work is going on to help give us better
insights into what is happening with our code on production.
Thanks
I wanted to say thanks to LivingSocial who lets me work some
of these tools and sends me around to some conferences. Also, if
you think any of this is interesting we are hiring.
Thanks for listening, hope you found some of this useful for
your applications.
/


WITNESS LIST Natural Resources Committee August 5, 2004 -10:00A Interim Charges ON: Alvarez, Ramon Scientist (Environmental Defense), Austin, TX Beard, Monica (Mobile Emissons Reduction Coalition), Austin, TX Beatty, George Consultant (Texas Environmental Research Consortiom), Houston, TX Bell, Peter (Distribution Drive), Addison, TX Beving, Rita Agency Owner (Dallas Sierra Club), Addison, TX Blume, Dana Environmental Affairs Program Coordinato (Port of Houston Authority), Houston, TX Boyle, Thomas D. (Self), Midlothian, TX Crites, James Executive Vice President Operations (DFW International Airport), Dallas/Fort Worth, TX Edlund, Carl Director (EPA), Dallas, TX Evans, Pat Mayor (City of Plano), Plano, TX Ferrer, Liz (Walsh Ranches Limited Partnership), Austin, TX Fischer, Nile (Self), Arlington, TX Grinnell, Joseph (Self), Palmer, TX Hammond, Wendi Executive Director (Blue Skies Alliance), Dallas, TX Harris, Ron County Judge (North Tx Clean Air Steering Committee, Tx Clean Air Working Group), McKinney, TX James, Jeremy (City of Victoria), Victoria, TX Kaminsky, Cynthia (Citizens for Responsible Economic Development), McKinney, TX Marquez, Ralph Commissioner (Texas Commission on Environmental Quality), Austin, TX McCracken, J. Guy (Texas Citizens Lobby), Grapevine, TX Meyer, Claudia (Self), Dallas, TX Newton, Jennifer (AGC of Texas), Austin, TX Parks, Jim General Manager (North Texas Municipal Water District), Wylie, TX Rooke, Molly (Public Citizen, Texas office), Dallas, TX Stansell, Wade Environmental Strategy Manager (TXU), Dallas, TX Taylor, Dub Director (State Energy Conservation Office), Austin, TX Thomas, Gary President/Executive Director (Dallas Area Rapid Transit), Dallas, TX Tull, Laura (Self), Fort Worth, TX Walker, Scheleen Air Quality Planner (Travis County Judge Samuel T. Biscoe), Austin, TX Whitmore, Eleanor Program Director (Texas Campaign for the Environment, Texas Trash Watch), Arlington, TX Yazdani, Bahman (Energy Systems Laboratory/ Tx A&M University), College Station, TX Registering, but not testifying: On: Chapman, Barney (Self), Clarksville, TX Harbour, Jan Polk (Self), Dallas, TX Hubener, Katy (Self), Grand Prairie, TX Louden Jr., G. Malcolm (Walsh Ranches, L.P.), Fort Worth, TX Matthews, David (Texans who like to breathe), Dallas, TX Traub, Marilyn (Self), Dallas, TX Providing written testimony: On: Smith, Deborah Angell (Democratic Party of Collin County), Dallas, TX


Databases & Codes
Saliency Detection
-
RSRCNN
Road structure refined CNN (RSRCNN)
|
GitHub
|
-
Raw video dataset
33 raw videos from the latest HEVC standard test sets, such as JCT-VC, which have been commonly utilized for evaluating HEVC performance. The eye fixations of all 32 subjects over each video frame were recorded by a Tobii TX300 eye tracker at a sample rate of 300 Hz.
|
GitHub
|
-
Large-scale eye-tracking database of videos (LEDOV)
LEDOV includes 538 videos with diverse content, containing a total of 179,336 frames and 6,431 seconds. The diverse content refers to the daily action, sports, social activity and art performance of human, and the videos of animal and man-man objects are also included. Moreover, 32 participants (18 males and 14 females), aging from 20 to 56 (32 on average), were recruited to participate in the eye-tracking experiment.
|
GitHub
|
-
Predicting salient face in multiple-face videos
Eye tracking data on multiple face videos.
|
GitHub
|
-
Natural-scene images memorability (NSIM) database
NSIM dataset includes 258 natura-scene images and their memorability scores.
|
GitHub
|
-
Face images for saliency detection
510 Face images for saliency detection.
|
GitHub
|
-
Face videos for saliency detection
Face videos for saliency detection.
|
GitHub
|
Video Compression
-
MFQE 2.0
The TensorFlow Code for testing multi-frame quality enhancement (MFQE) approach v2.0.
|
GitHub
|
北航云盘
|
-
Database for HEVC in-loop filter
A large-scale database for HEVC in-loop filter (HIF).
|
GitHub |
-
Subjective-driven complexity control approach for HEVC
Subjective-driven Complexity Control Source Code.
|
GitHub
|
-
Eye-tracking database for 40 typical images
An eye-tracking database for 40 typical images.
|
Google Drive
|
-
Database for CU partition of HEVC (CPH)
A large-scale database for CU partition of HEVC, to reduce encoding complexity through deep learning based approach.
|
GitHub (Database)
|
GitHub (Code)
|
-
DS-CNN
The Caffe code of the decoder-side scalable convolutional neural network (DS-CNN)
|
GitHub
|
-
RTE core
The core code for the recursive Taylor expansion (RTE) method
|
Google Sites
|
-
Weight-based R-lambda RC
The core code for the weight-based R-lambda rate control
|
Google Sites
|
Virtual/Augmented Reality
-
VQA-ODV
A large-scale VQA dataset of omnidirectional video proposed in ACMMM 2018 paper.
|
GitHub
|
-
PVS-HMEM database
PVS-HMEM (Panoramic Video Sequences with Head Movement & Eye Movement database) database contains both Head Movement and Eye Movement data of 58 subjects on 76 panoramic videos.
|
GitHub
|
-
V-CNN
Viewport-based CNN for visual quality assessment on 360° video.
|
GitHub
|
-
NCP- and CP-PSNR
Perceptual objective quality assessment methods of omnidirectional video.
|
GitHub
|
-
Panoramic video head tracking data
HTC Vive head tracking data of 40 subjects on 48 panoramic video sequences in 8 classes.
|
GitHub
|
-
Evaluation_VR
A subjective evaluation tool on VR video with GUI in MATLAB. SSCQS and MSCQS method are provided for different aims.
|
GitHub
|


{% extends 'default.html' %} {% block title %}{{ title }}{% endblock %} {% block content %}
Are you sure what you want to delete this car?


Fitness Tracker
Add Workouts
Workout Dashboard
Zero Workouts!!!
×
There is no workouts please add them.


The digitisation of The Straits Times' 170-year-old archive has made it possible to carry out intense data analysis on the newspaper's online archive and capture the mood of the era in which the news stories appeared. This visualisation does that by highlighting keywords which appeared each year in The Straits Times, since 1845, and the stories that set the context for the keywords. The result is a dynamic portrayal of the changing buzzwords and social sentiment over time, which mirror Singapore's evolution.


climate change tick disease Lyme health Vibrio Ogden temperature Climate Canada studies Health PMID: risk data increase scapularis attribution attributed cases population populations {border-style Change associated emergence mortality change. deaths px;} #ffffff;} number (e.g., Baltic heatwave ticks geographic infections range warming Environ observed weather Ixodes Lindsay SST evidence temperatures D&A Sea Semenza detection distribution Detection Leighton burgdorferi changes factors heat-related human model outcomes reported spatial vector Perspect anthropogenic approach changing conditions different exposure impacts increased occurrence recent significant summer used Cramer Ebi North areas based climate-sensitive extent natural pattern patterns surveillance using variability water Attribution Baker-Austin Borrelia Disease approaches case determine eastern estimate event heatwaves impact period px; reference southern {font-family Canada, Sweden United University affecting analysis burden change, changed drivers effects estimated example, extreme font-size high infection mean northern possible rate study Barker European IPCC New Prüss-Üstün Report affected assessment attributable collab: current determinants double; early global heat higher including increasing influence likely long-term low occurred ocean proportion surface time time, transmission wound ./ehp. ./nature Attributing Based Bouchard Canada. EHP Entomol Environmental Europe However, June Koffi Med National Nature Panel Public Reid abundance, ambient analyses associations border-color border-width burdens climatic diseases environmental expansion extremes field future habitat health. hosts marine maximum numbers parahaemolyticus projected projections public region sea sites solid; species spread statistical typically understanding variables vector-borne vulnificus years {font-style {font-weight (and Appl Atlantic Background Bigras-Poulin CDC Charron Corvalán Emergence Evidence Field Global Infect Institute Int Intergovernmental Meteorological Rev Stone Stott Vezzulli [], a). agent alternative area attribute b). bacteria better bold cases, cause caused coastal concluded consequences considered courier; decades decades, detected disease, diversity elevated em; empirical establishment events exceeded expected gas greater greenhouse health, highly host include key lifecycle limit links locations means mortality. multiple occurring outbreaks particular passive potential probability process provide pt;} rates regional requires response risks scale second showed threshold trend use vectors year


A word of caution
For the reasons the author just listed, it should be obvious that a person should be very careful about displaying any special abilities to people that a person can't trust completely. Some people get away with performing miracles in public under the guise of performing “magic tricks”.
Regardless of what means a person uses to protect himself, be careful to cover a persons tracks. Also, be aware that performing a manifestation on a persons own, in a quiet, safe, comfortable, familiar environment is completely different then attempting the same act in front of an audience… even if that audience is just a friend or family member.
Understand that it is human nature to fear what is unknown. It is very possible that people you show, even people you considered close friends could become fearful of you. Be careful not to make people uncomfortable or you could even lose friendships. People like the status quo. That’s why the herd mentality is so common and so hard to break away from for some people.
If a person absolutely must demonstrate an ability to someone, use the most trivial and unassuming example as that a person can think of. For example changing the way the needle on a compass points without touching it is a relatively undramatic demonstration, and is less likely to promote a fearful response from a persons audience than, say, levitating the whole compass, or teleporting it across the room.
Step lightly! These are traps that could get a person labeled as a “Flake”, a “Freak”, or if a person are careless enough, could even end up with a person being brought in to a hospital for observation.
It is better to be cautious and wise than to be reckless. For a friend that is about to be sick, a person could always say something like “I’ve been feeling a little under the weather lately, how are a person feeling?” Or, play off of something less mysterious, like “a person look tired. Are a person feeling ok?”
In short: Avoid flaunting a persons abilities!
Some final words of caution: Many of the training exercises listed in this book can and will alter a persons normal state of consciousness. They should never be done immediately before swimming, driving, operating heavy machinery or anything where a lapse of attention could be harmful to a personsself or others.
This brings me to the fact that the author am not a Doctor and am not qualified to speculate on any potential dangers involved in doing any of these exercises.
The reader assumes all risks associated with these exercises.
Only a person can be responsible for a persons own well being. If a person are performing an exercise from this book and something feels wrong, then STOP.
Please, please, please, use common sense while doing these exercises and when using your amazing abilities.
When you are still interested in learning how to manifest some tangible psychic skills, then keep reading… a person are in for a heck of a ride!


 The Dyslexie font is also available as a
free download
.


22519
cdn06.00-Down
75.57
D
22520
cdn06.01-Down
74.73
D
22521
cdn06.02-Down
77.43
D
Technology
Training and Education
Head office support


|
BlockSnake
|
#include <SnakeBody.hpp>
Public Member Functions | |
| void | addBody () |
| bool | doesCollideWithBody (Vector3f pos) const |
| void | move (Vector3f pos) |
| SnakeBody (AssetManager *assetManager, unsigned short next, Vector3f position) | |
| Public Member Functions inherited from GameObject | |
| Vector3f | getPosition () const |
| bool | canCollide () const |
| virtual | ~GameObject () |
Protected Member Functions | |
| virtual void | update (float) override |
| virtual void | onDestroy () override |
| virtual void | draw (float) override |
| Protected Member Functions inherited from GameObject | |
| Matrix4x4< float > | getCurrentMat (float aspect) |
| virtual void | onKeyDown (unsigned short keycode) |
| virtual void | onCollision (GameObject *col) |
Private Attributes | |
| friend | SnakeHead |
| SnakeBody * | nextBody |
| AssetManager * | assetManager |
| int | snakeBodyProgram |
| int | texture |
| int | primitive |
| GLint | mv_location |
Additional Inherited Members | |
| Protected Attributes inherited from GameObject | |
| Vector3f | position |
| bool | doesCollide |
| Vector3f | scale |
| Vector3f | rotation |
The body of the snake
| SnakeBody::SnakeBody | ( | AssetManager * | assetManager, |
| unsigned short | next, | ||
| Vector3f | position | ||
| ) |
Initializes the body of a snake
| assetManager | The management of resources |
| next | How many snakebodies are next |
| position | the initializing position |
| void SnakeBody::addBody | ( | ) |
Increases the body size
| bool SnakeBody::doesCollideWithBody | ( | Vector3f | pos | ) | const |
Checks if the body collides with the head
| pos | The position of the head |
|
overrideprotectedvirtual |
Implements GameObject.
| void SnakeBody::move | ( | Vector3f | pos | ) |
Moves the bodies
| pos | The new position |
|
overrideprotectedvirtual |
Reimplemented from GameObject.
|
overrideprotectedvirtual |
Implements GameObject.
|
private |
The assetManager
|
private |
|
private |
The body is recursive..
|
private |
the mesh reference
|
private |
The opengl program reference
|
private |
|
private |
the texture reference


Welcome to our resort!
Please use these links to navigate the site:
Accomodations
Activities
Contact Details
Pictures of the Resort
Travel
We hope you enjoy your stay!


Alexander Korn
Resume
Dropdown
Link 1
Link 2
Link 3
DROPDOWN
Link 1
Link 2
Link 3
About Me
Currently employed as a Software Engineer at
Beckman Coulter
Portfolio
Social Media


With subsumption its okay for some transitions of n1 to be unmatched with
any transitions in n2, but all of n2 transitions must be matched to some
transition in n1.
Tests the KTails algorithm in synoptic.algorithms.bisim.KTails
TODO: A good way of testing subsumption (once its implemented) is to create a
random graph g, and then to create a new graph g' that is identical to g
except some of the nodes\edges are missing.


Vierges
Vierges is a movie starring Joy Rieger, Michael Aloni, and Manuel Elkaslassy. In Kiryat Yam, small town on the north coast of Israel, everything seems to have stopped. Lana, a rebellious teenager, vowed to fight against resignation...


Edit document's content. Documents can have arbitrary fields (click on 'add field' to create a new one). To remove a field click on the X icon on the right of the field. Once finished click on "Save' to make changes permanent.
Graph


Three Major Problems I'm Having with Synergy 3.0
-
Charity
Hi there,
I tried Synergy 2.9 out a while back, loved it and vowed that when I had some cash to get a license (I know you have to be seriously out of pocket not to be able to afford it, but well, I was!) Today I went to buy a lisence code and found that version 3.0 is now out. So I thought I'd download that and test it and I've found it has some problems for me that 2.9 didn't, so I just want to sort those before I buy a code, or at least make sure I can down-grade to 2.9 if my problems can't be solved in 3.0.
My issues are:
1. I can no longer rate songs using hot keys, which was the main reason I wanted Synergy. All my other hot keys work great, it's just those used to assign ratings that don't. I neither get the visual feedback image, nor do the ratings for the songs actaully change in iTunes. I've included a picture to show how I've assigned my hot keys. http://i19.photobucket.com/albums/b163/HeavenOnEarth/Picture416-57-20.png I can't see that this would create any conflicts with short cuts in other apps. I've tried the shortcut whilst in various apps, and also whilst in iTunes, and it doesn't work in any. They worked in 2.9, but not in 3.0. I don't want to change the keys I'm using unless absolutely necessary by the way, as I really liked them how they were.
2. My playlists will not show up in the Global menu. Only 'refresh' is listed, and when I click on that, nothing happens. Even when I go back a while later, there is still nothing. This also worked in 2.9.
3. Not sure if this is a personal issue just for me or for all users, but I am confused about how Synergy displays artwork in the floater panel. I don't know how it works currently, but I know how I would like it to work, and that's for it to always get it's artwork from iTunes, without ever connecting to the net. It doesn't seem to be doing that for me at the moment, occasionally it seems to use my iTunes artwork, but often I'll just get a question mark show up, even when the song has artwork in iTunes. I feel Synergy needs to have the option to simply fetch the art from iTunes for all songs, especially now, with iTunes 7, where art plays a big part in the experience of using iTunes, so many people will have filled their whole library with art, carefully choosing which images they want. Not all users like whatever iTunes or Synergy would fetch... for example, one user I know uses pictures of the artist, rather than album artwork. I don't do anything that weird, but I have selected all my artwork carefully and would like it displayed in the floater.
For your info; I have Mac OS X 10.4.7, iTunes 7.0 (I know both are one version behind; could that be causing problems?) Also, when I installed Synergy 2.9, I installed it to work only on my user account on this machine, then when I installed 3.0, I installed it to be usable by all users on this machine. I used the normal installer not the expert method. The old version of synergy seems to have been deleted properly, as there are files from it in the trash, so hopefully, I didn't cause problems by changing how many users were able to access Synergy when I installed the new version?
I'd appreciate any responses to help me deal with these 3 problems, as these problems are currently making Synergy unusable for me. As soon as I can sort these out I'll be buying license code. Thanks, Charity
-
Greg Hurrell
Originally Posted By: Charity1. I can no longer rate songs using hot keys, which was the main reason I wanted Synergy. All my other hot keys work great, it's just those used to assign ratings that don't. I neither get the visual feedback image, nor do the ratings for the songs actaully change in iTunes. I've included a picture to show how I've assigned my hot keys. http://i19.photobucket.com/albums/b163/HeavenOnEarth/Picture416-57-20.png I can't see that this would create any conflicts with short cuts in other apps. I've tried the shortcut whilst in various apps, and also whilst in iTunes, and it doesn't work in any. They worked in 2.9, but not in 3.0. I don't want to change the keys I'm using unless absolutely necessary by the way, as I really liked them how they were. There are no differences in the hot key handling between 3.0 and 2.9. You've chosen keyboard shortcuts that are in conflict with other applications. Control+Something is a particularly common combination, especially in the case of Control+Arrow. You may not have noticed this with 2.9 but that's because when you tried it out you probably had a different application frontmost. If the frontmost application responds to those key strokes, Synergy will never see them. In order to work around this problem you'll need to select some other shortcuts. Quote:2. My playlists will not show up in the Global menu. Only 'refresh' is listed, and when I click on that, nothing happens. Even when I go back a while later, there is still nothing. This also worked in 2.9. I can't reproduce that issue here. Have you tried deleting your preferences file or any other the other trouble-shooting tricks listed here? Quote:3. Not sure if this is a personal issue just for me or for all users, but I am confused about how Synergy displays artwork in the floater panel. I don't know how it works currently, but I know how I would like it to work, and that's for it to always get it's artwork from iTunes, without ever connecting to the net. It doesn't seem to be doing that for me at the moment, occasionally it seems to use my iTunes artwork, but often I'll just get a question mark show up, even when the song has artwork in iTunes. Most questions about how the feature operates are answered here. There are also quite a lot of threads on these forums which may prove of interest. Quote:I feel Synergy needs to have the option to simply fetch the art from iTunes for all songs, especially now, with iTunes 7, where art plays a big part in the experience of using iTunes, so many people will have filled their whole library with art, carefully choosing which images they want. Not all users like whatever iTunes or Synergy would fetch... There are a number of feature requests related to cover art open in the bugs and feature requests database. The most relevant one here is probably:
https://wincent.com/a/support/bugs/show_bug.cgi?id=54
Quote:Also, when I installed Synergy 2.9, I installed it to work only on my user account on this machine, then when I installed 3.0, I installed it to be usable by all users on this machine. I used the normal installer not the expert method. The old version of synergy seems to have been deleted properly, as there are files from it in the trash, so hopefully, I didn't cause problems by changing how many users were able to access Synergy when I installed the new version?
It depends on what user account you are trying to use Synergy from. If you installed it in "User A" account first, and then installed it for all users within "User A" account, the installer should have removed the local install first so there will be no conflict. But if you installed for all users from "User B" account, then it won't (and can't) have cleaned up the old install in "User A" account. If in doubt, the most certain course is to remove the old install(s) and do a clean install.
-
Charity
About the problems with playlists, I now have those back. I didn't do anything, they just appeared!
As for how I installed it, well I installed from the same user account each time, so that should be fine. Thanks for the info on that.
About the art issue, it seems to be working now i.e. it's always displaying the art I've assigned songs in iTunes. Before it was either displaying stuff from the net, or an old image I have since changed, or nothing at all. I'm not sure what fixed it, I did de-select, then re-select the option for what Synergy displays in the preferences, clicking on 'apply' each time, maybe that re-set it? I also deleted any album art in the Synergy covers folder, and that made sure it definately uses my art, not art I don't want from the net or art I used when I had 2.9 but have now updated.
Quote:There are no differences in the hot key handling between 3.0 and 2.9. You've chosen keyboard shortcuts that are in conflict with other applications. Control+Something is a particularly common combination, especially in the case of Control+Arrow. You may not have noticed this with 2.9 but that's because when you tried it out you probably had a different application frontmost. If the frontmost application responds to those key strokes, Synergy will never see them. In order to work around this problem you'll need to select some other shortcuts.
I don't think this is why the shortcuts weren't working, as I tried them in various applications, including ones in which they worked with Synergy 2.9. Some of the apps I used have been updated between the times I was using Synergy, but the old shortcuts didn't seem to work in any apps, even Stickies, and that's not been updated.
Despite this, I have now changed the keys, by adding shift to all the actions, so now all my key combos are ctrl + shift + something else. Does that sound like it would work in most apps? It's definitely working in the ones I'm currently trying it in, just want to check it's not too much of a common combo.
Thanks for your time.
-
Greg Hurrell
Originally Posted By: CharityThis is not why the shortcuts weren't working, as I tried them in various applications, including ones in which they worked with Synergy 2.9.
You could always go back to Synergy 2.9 and make a comparison, but I think you'll find that it performs identically to 3.0.
Quote:Despite this, I have now changed the keys, by adding shift to all the actions, so now all my key combos are ctrl + shift + something else. Does that sound like it would work in most apps? It's definitely working in the ones I'm currently trying it in, just want to check it's not too much of a common combo.
It depends on which apps you're running, but Control+Shift is definitely better than just Control. The trouble with keys like Control+Arrow is that they are used by just about every application that works with text; for example, when I press Control+Arrow in the application I'm writing this in (Safari) it is used for cursor movement. Even Control+Shift+Something will be used by some applications, but I imagine that it will be less common.
Quote:About the art issue, I read the page of information about it, and it seem Synergy isn't working for me as described there. It doesn't display art that's embedded in songs in iTunes for every song, only the occasional few, and for those I'm not sure if it's using my art or fetching art from the net.
You can find out by choosing "Show Album Covers Folder" from the Synergy Global menu when such a song is playing. If it is a downloaded cover you'll see it selected in the Finder in the "Album Covers" folder; if it is a song supplied by iTunes you'll see it in the "Temporary Album Covers" folder.
Quote:I've done everything I think I should do; I'm not playing music from across a network and I have the option for showing album art selected in Synergy's preferences, so I'm not sure what's wrong. I looked at the form you pointed me to; and I'm afraid I found it very confusing, so I didn't fill it out. Any advice on what to do about that?
If you can find a music file which has album art in it but which Synergy does not seem to receiving the art from iTunes, can you send me the file and I will see if I can reproduce the problem here? You can send it as an email attachment to "win" at this domain.
-
Charity
Wow that was quick! Please have another look at my post, as I edited it whilst you were replying.
-
Greg Hurrell
Originally Posted By: CharityAbout the art issue, it seems to be working now i.e. it's always displaying the art I've assigned songs in iTunes. Before it was either displaying stuff from the net, or an old image I have since changed, or nothing at all.
Unfortunately it will prioritize the "old stuff" over what's in iTunes. This is a known issue (see https://wincent.com/a/support/bugs/show_bug.cgi?id=54). For the time-being the only way to force Synergy to use the new art is to delete the downloaded art that you no longer want to use.
Quote:I'm not sure what fixed it, I did de-select, then re-select the option for what Synergy displays in the preferences, clicking on 'apply' each time, maybe that re-set it? I also deleted any album art in the Synergy covers folder, and that made sure it definately uses my art, not art I don't want from the net or art I used when I had 2.9 but have now updated.
Yes, that's right. Deleting the unwanted art was a necessary step. Also note that when you delete such art Synergy will pick up the change the next time you play the track.
-
Charity
What I meant was that as well as deleting old art, I also tinkered with the preferences. I had it set to display cover art, which I changed to one of the other options, clicked apply, then changed back to display cover art, and clicked apply again... maybe that helped too?
-
Greg Hurrell
Originally Posted By: CharityWhat I meant was that as well as deleting old art, I also tinkered with the preferences. I had it set to display cover art, which I changed to one of the other options, clicked apply, then changed back to display cover art, and clicked apply again... maybe that helped too? It shouldn't help, unless you had a corrupt preferences file, in which case clicking "Apply" may have had the effect of writing out a new preferences file.
-
Charity
Well thanks for your help Wincent, you've been very helpful. I'm on another forum at the moment trying to get help with some software, I wish that developer was as helpful as you've been!
I look forward to seeing where Synergy goes in the future. It's a great app now, the kind of functions iTunes would do well to provide itself. The only thing I have found difficult is that the website is quite detailed and a little hard to understand for someone who's not really technically-minded so that may put some people off. I mean that just as constructive criticism. For example, the difference between Synergy and Synergy Advance isn't immediately obvious without reading quite a bit, and there is no simple list (that I could see) of what Synergy Advance offers that Synergy does not. It seemed to me the only way you could work that out would be to read the version history of Synergy Advance. For now, I've decided just to use Synergy until it is replaced by Synergy Advance.
-
Greg Hurrell
Yes, I agree the website could be (and should be simpler). As time goes by I'm aiming to make it simpler and simpler. The detailed content will still be there, but you will have to dig for it a little deeper; all the basic stuff will be much more up front and easy to find.
-
Charity
Great, that's just what I think would work. Websites that are really simple where you can't access more detailed content are just as annoying for the technically-minded as ones where all the content is complicated are for the non technically-minded. One that has both simple info presented attractively and detalied info more out-of-immediate view cater for all ability levels.
Thanks again for your time.
-
Greg Hurrell
Yes, I think it's partly due to the influence of Apple and their very clean product pages:
http://www.apple.com/ilife/iphoto/ http://www.apple.com/ilife/iweb/ http://www.apple.com/ilife/imovie/ http://www.apple.com/ilife/idvd/ http://www.apple.com/ilife/garageband/ http://www.apple.com/iwork/keynote/ http://www.apple.com/iwork/pages/
And also partly due to the "Web 2.0" aesthetic as represented by extremely simple sites like this:
http://www.37signals.com/ http://www.flickr.com/
So over the last couple of years many, many, many independent Mac software houses have started to make their pages look more and more like Apple's. The more popular houses have started to design extremely attractive, simple pages that look like this:
And the smaller houses have followed suit:
There are many, many examples out there but those links above give the basic idea.
The general trend seems to be:
Fewer words per pageA focus on simple languageSimple navigation"Shallow" sites: not many "levels" deepMore graphicsHigher "production values"Fewer words overall!
As you've noted, this trend can be taken too far and you can end up with a website that contains only a few pages of information and doesn't really provide in-depth information about a product.
Seems to me that text-heavy websites are considered less and less navigable nowadays, which is a key difference from when I started, where putting more text on your website made it perceived as a more valuable resource.
Let's take one example of a very text-heavy page on this site:
https://wincent.com/a/products/synergy-advance/help/preferences/advanced/
Obviously that sort of text shouldn't be up front where nobody will have the inclination to wade through it (and indeed, it's not up-front), but the information needs to be somewhere... My current inclination is that in the future I need to make the following changes:
Less text in general on all the "top-level" or "entry" pagesVery simple navigationVery simple, brief langaugeDetailed help is useful, but it should be broken up into very small chunks, not monolithic pagesTo make that help useful it should be easily searchableThis suggests that help should be embedded inside applications and viewed with the Apple Help Viewer (for searchability) even if it means making downloads a little largerThe focus of the website will therefore shift towards pre-sale support, whereas after-sale support will often be met by the in-application help (if it's good enough)For completeness, the in-application help should be mirrored somewhere on the site (where Google can find it)
-
Charity
That sounds like a good guide to anyone creating a website for software sales, and I'm sure the advice would apply to other types of websites too. Maybe wordy sites used to be more popular because less people used to use computers & software, and those that did tended to know what they were doing quite well. Now, many more people use computers, many of which are more novice, who may not have (or be interested in aquiring) such technical knowledge. There's a phrase I've heard alot of times; "KISS; Keep It Simple, Stupid!" I think nowadays with the number of people who use computers rising all the time, that's an important thing to remember.
I've realised the more I've been using a Mac how much Apple does this; they sometimes overly simplify info to make their product seem a little easier to use than it actually is. For example, they don't tell you to repair permissions before and after installing an OS update, you have to kind of find that out yourself.
I especially think it's an important point about dividing help into small chunks; that's something I wouldn't have thought of, but it does make it easier. A subtle but important point.
The only thing I'd add to your tips is to make to site attractive aesthetically. I think that people tend to think sites are more professional if it looks attractive, shallow though that sounds. It's that old judging on first impressions thing.
I think it's good for the support to be mainly in the Help Viewer, although I don't think that should replace user forums because they can answer specialised questions the help may not. That said, a good help guide should answer most questions itself. You provided a link to the hog bay software site, which I have recently been using, as I've just begun trying out Mori. I had to ask a question or two in their help forums that I felt could have been answered in the help, but weren't.
-
Charity
Also, what did you mean by higher production values? I've not come across that phrase before.
-
Greg Hurrell
Originally Posted By: CharityAlso, what did you mean by higher production values? I've not come across that phrase before.
Basically what you said about things looking better and being more polished:
-
Charity
Ahh ok. Thanks.
Reply
This topic is now closed.


{% extends 'base.html' %} {% block content %}
General knowledge questions and answers help a child to grow both on the personal and academic level. Kids always use to rote things and it is really important to make them learn instead of rote. And this is important to take some twist in their studies by introducing general knowledge quizzes at both the places home and school. Even when kids watch TV or mobile phone, they specifically watch either cartoons or play games that would not help in increasing their general knowledge.
Through GK questions, kids can analyze the situation better.In this application, users can sign up as a student or a teacher. Teachers can create quizzes and students can answer quizzes based on their interests.
{% endblock %}


B.A.
CFA, CFP, CPA
President, Hummer Financial Advisory Services Inc.,
an SEC-registered investment advisor
B.S., M.A.S. Accounting, University of Illinois, Urbana, Illinois
Selected past experiences:
Audit Supervisor, Peat Marwick Mitchell & Co (now KPMG);
Director of LaSalle Bancorp, LaSalle, Illinois;
Corporate Controller, Matex Corp; Registered Representative;
Licensed Insurance Agent; Investment Portfolio Manager.
B.S. Finance


| Number of Classes | Line Coverage | Mutation Coverage | Mutation Score |
|---|---|---|---|
| 7 | 74% | 62% | 85%
Killed: 56
Uncertain: 2
|
| Name | Line Coverage | Mutation Coverage | Mutation Score |
|---|---|---|---|
| EncodedSegment.java | 100% |
78% |
100%
Killed: 2
Uncertain: 0
|
| FirstSupportingMessageSplitter.java | 91% |
71% |
83%
Killed: 5
Uncertain: 0
|
| GsmBasicCharsetExtensionTableCounter.java | 100% |
50% |
100%
Killed: 17
Uncertain: 0
|
| GsmMessageSplitter.java | 83% |
66% |
88%
Killed: 29
Uncertain: 2
|
| NoSplitMessageSplitter.java | 50% |
40% |
67%
Killed: 2
Uncertain: 0
|
| RandomReferenceNumberGenerator.java | 100% |
33% |
50%
Killed: 1
Uncertain: 0
|
| StringSegment.java | 0% |
0% |
0%
Killed: 0
Uncertain: 0
|


[1]
you can record three disc or more on one battery charge.
[2]
It is 200 bucks cheaper than my sony digi 8s back when sony made a good product.


Ensure that accounts are locked after consecutive failed login attempts.
Multiple, consecutive failed authentication attempts over a short period of time are a symptom that is used to detect when an account is under attack. Locking out the account prevents the attacker from compromising and accessing the account.
Follow these steps to ensure your application will lock out an account after consecutive failed login attempts:
Verify that your application has a lockout policy. An account lockout policy is typically application specific. Review your application's requirements and design specifications and verify the following functionality:
Ensure your application tracks login attempts. All authentication procedures record the number of authentication attempts for each user. The login counter for each user should be reset to 0 upon a successful authentication
Ensure your application enforces the lockout policy. All authentication procedures implement your application's lockout policy. The implementation should match the lockout policy as the business requirements of your organization may change over time
Test the application. Use a web browser to test authentication to make sure that repeated failed authentication attempts result in the user account being locked.
Use the following steps to successfully lock accounts after consecutive failed login attempts:
Define a lockout policy. There are two variables to consider when determining a lockout policy:
A simple policy would be to lock an account after five failed login attempts for the duration of 15 minutes. Although this is an effective method for blocking a brute force attack, it exposes your application to denial of service as an attacker can easily keep an account locked through a small stream of authentication requests.
When determining the lockout policy, it is important to evaluate the risk of attacks against the user and the support costs associated with reactivating a locked account. For example, requiring the user to contact your organization's support staff to reactivate a locked account will have a direct impact on support costs and would add general user frustration. However, it is important to use extra care when designing more sophisticated variations of your application's lockout policy, such as correlating a single or multiple user login attempts with a source IP. When adding extra levels of complexity, carefully consider and evaluate the scenarios where your application's lockout policy can be circumvented or can harm your business. For instance, consider scenarios where an attacker would attempt to compromise a user through the use of multiple hosts, or multiple users would authenticate using a shared office IP.
Note: PCI DSS requirements state that an account should be locked out for at least 30 minutes after no more than six failed login attempts.
Track login attempts. Login attempts can be tracked with the use of a login counter. Increment the counter once a user tries to authenticate. Reset the counter to 0 after the user successfully authenticates.
Enforce the lockout policy. The lockout policy should be enforced at all points in the application where authentication is necessary.
Set an unlocking mechanism. Keep track of the lockout period. Based on your application's lockout policy, unlock the account after the lockout period has expired.


Google Map
Vector Map
Calendar
Log out
Production Plan
Select Style
Select Plant
Select Month
Enter Production
For all plants
Planned Production
Planned Shipment
Date
Plant 1
Plant 2
Plant 3
Plant 4
Plant 5
Plant 6
Plant 7
Total
Remarks
Plant 1
Plant 2
Plant 3
Plant 4
Plant 5
Plant 6
Plant 7
Total
Remarks
1
Enter Production
For single plant
Planned Production
Planned Shipment
Date
Plant 1
Total
Remarks
Plant 1
Total
Remarks
1