ParentClub: Brilliant ideas for happier families
ParentClub website is full of great ways to entertain kids and help parents.
by Record ReporterYOU don’t need to be a rocket scientist to raise kids – just need to trust your instincts and do your best.
As every parent – or anyone who looks after kids – knows, it’s a roller coaster of ups and downs.
From the special moments, such as the chats that leave you laughing and the pictures they draw for the fridge, to the battles over screen time, homework meltdowns, or shopping strops – parenting challenges remain the same.
It’s handy to have an arsenal of tricks up your sleeve that you can pull out when the going gets tough.
The Scottish Government’s campaign helps make parents’ and carers lives easier with brilliant ways to tackle tricky times.
Its ParentClub website is full of little things you can try out to keep the kids busy – and lower stress levels. The ideas are simple and either free or cheap to do and have come from parents, so are tried and tested.
Wonder how to unstick them from their screens? Getting them to make a poster of their favourite game or app is a good way to keep them busy.
Or need a way to divert them from a huff? Try space travel – writing a list of everything they’d need for a trip to space is a fun way to keep them happy.
ParentClub has many more tips to help the parents and carers of primary aged children. During the next few weeks, we will talk to parents to understand their challenges and hear how they deal with screens, shopping, and managing time with a small person.
Nicole Stewart, from Kilwinning, Ayrshire, is mum to Leo, four, who has just started Primary One.
A nurse, Nicole, 28, has some great advice for other parents.
She says: “I think screen time is quite important now because kids are growing up in that generation where everyone has them.
“But we like to limit it, especially before bedtime or homework, because it can make him quite hyper,” she says.
“We take the iPad away and do things like reading a book before bedtime or taking him outside on his bike during the day.
“After school, when Leo’s a bit grumpy, often it’s because he’s hungry.
“And out shopping, we give him a list, but we use pictures and a number of how many we need – it keeps him interested and it’s almost like a treasure hunt.”
Simple fun and games to make children smile again
• IF THEY’RE ABOUT TO GO OFF IN A HUFF, try space travel. Writing a list of everything they need for a trip to space is a fun way to keep them busy.
• TO UNSTICK THEM FROM THEIR SCREENS, try poster play. Getting them to make a poster of their favourite game or app is an engaging way to occupy them.
 Measure their height and compare it to different animals.
 Asking them to find all the items on your list for less than £1 can make the trip entertaining.
• For more parenting ideas, tips and hints visit parentclub.scot


After installing the module, yon should go to Settings and create an attachment (background image)
Select an image, put a checkmark in the "Use as login page background" checkbox and click on Save button
Now, turning to the login page, you can see the downloaded background
The module allows to use unlimited number of images for the background. In this case, an image will be selected and changed randomly. For example, if we reload the above login page, the background will be changed.
It must be noted that a background images can be adapted to any size screen.
Contact us by email or fill out request form


The amcheck
module provides functions that allow you to
verify the logical consistency of the structure of relations. If the
structure appears to be valid, no error is raised.
The functions verify various invariants in the
structure of the representation of particular relations. The
correctness of the access method functions behind index scans and
other important operations relies on these invariants always
holding. For example, certain functions verify, among other things,
that all B-Tree pages have items in “logical” order (e.g.,
for B-Tree indexes on text
, index tuples should be in
collated lexical order). If that particular invariant somehow fails
to hold, we can expect binary searches on the affected page to
incorrectly guide index scans, resulting in wrong answers to SQL
queries.
Verification is performed using the same procedures as those used by index scans themselves, which may be user-defined operator class code. For example, B-Tree index verification relies on comparisons made with one or more B-Tree support function 1 routines. See Section 37.16.3 for details of operator class support functions.
amcheck
functions may only be used by superusers.
bt_index_check(index regclass, heapallindexed boolean) returns void
bt_index_check
tests that its target, a
B-Tree index, respects a variety of invariants. Example usage:
test=# SELECT bt_index_check(index => c.oid, heapallindexed => i.indisunique), c.relname, c.relpages FROM pg_index i JOIN pg_opclass op ON i.indclass[0] = op.oid JOIN pg_am am ON op.opcmethod = am.oid JOIN pg_class c ON i.indexrelid = c.oid JOIN pg_namespace n ON c.relnamespace = n.oid WHERE am.amname = 'btree' AND n.nspname = 'pg_catalog' -- Don't check temp tables, which may be from another session: AND c.relpersistence != 't' -- Function may throw an error when this is omitted: AND c.relkind = 'i' AND i.indisready AND i.indisvalid ORDER BY c.relpages DESC LIMIT 10; bt_index_check | relname | relpages ----------------+---------------------------------+---------- | pg_depend_reference_index | 43 | pg_depend_depender_index | 40 | pg_proc_proname_args_nsp_index | 31 | pg_description_o_c_o_index | 21 | pg_attribute_relid_attnam_index | 14 | pg_proc_oid_index | 10 | pg_attribute_relid_attnum_index | 9 | pg_amproc_fam_proc_index | 5 | pg_amop_opr_fam_index | 5 | pg_amop_fam_strat_index | 5 (10 rows)
This example shows a session that performs verification of the
10 largest catalog indexes in the database “test”.
Verification of the presence of heap tuples as index tuples is
requested for the subset that are unique indexes. Since no
error is raised, all indexes tested appear to be logically
consistent. Naturally, this query could easily be changed to
call bt_index_check
for every index in the
database where verification is supported.
bt_index_check
acquires an AccessShareLock
on the target index and the heap relation it belongs to. This lock mode
is the same lock mode acquired on relations by simple
SELECT
statements.
bt_index_check
does not verify invariants
that span child/parent relationships, but will verify the
presence of all heap tuples as index tuples within the index
when heapallindexed
is
true
. When a routine, lightweight test for
corruption is required in a live production environment, using
bt_index_check
often provides the best
trade-off between thoroughness of verification and limiting the
impact on application performance and availability.
bt_index_parent_check(index regclass, heapallindexed boolean, rootdescend boolean) returns void
bt_index_parent_check
tests that its
target, a B-Tree index, respects a variety of invariants.
Optionally, when the heapallindexed
argument is true
, the function verifies the
presence of all heap tuples that should be found within the
index, and that there are no missing downlinks in the index
structure. When the optional rootdescend
argument is true
, verification re-finds
tuples on the leaf level by performing a new search from the
root page for each tuple. The checks that can be performed by
bt_index_parent_check
are a superset of the
checks that can be performed by bt_index_check
.
bt_index_parent_check
can be thought of as
a more thorough variant of bt_index_check
:
unlike bt_index_check
,
bt_index_parent_check
also checks
invariants that span parent/child relationships.
bt_index_parent_check
follows the general
convention of raising an error if it finds a logical
inconsistency or other problem.
A ShareLock
is required on the target index by
bt_index_parent_check
(a
ShareLock
is also acquired on the heap relation).
These locks prevent concurrent data modification from
INSERT
, UPDATE
, and DELETE
commands. The locks also prevent the underlying relation from
being concurrently processed by VACUUM
, as well as
all other utility commands. Note that the function holds locks
only while running, not for the entire transaction.
bt_index_parent_check
's additional
verification is more likely to detect various pathological
cases. These cases may involve an incorrectly implemented
B-Tree operator class used by the index that is checked, or,
hypothetically, undiscovered bugs in the underlying B-Tree index
access method code. Note that
bt_index_parent_check
cannot be used when
Hot Standby mode is enabled (i.e., on read-only physical
replicas), unlike bt_index_check
.
heapallindexed
Verification
When the heapallindexed
argument to
verification functions is true
, an additional
phase of verification is performed against the table associated with
the target index relation. This consists of a “dummy”
CREATE INDEX
operation, which checks for the
presence of all hypothetical new index tuples against a temporary,
in-memory summarizing structure (this is built when needed during
the basic first phase of verification). The summarizing structure
“fingerprints” every tuple found within the target
index. The high level principle behind
heapallindexed
verification is that a new
index that is equivalent to the existing, target index must only
have entries that can be found in the existing structure.
The additional heapallindexed
phase adds
significant overhead: verification will typically take several times
longer. However, there is no change to the relation-level locks
acquired when heapallindexed
verification is
performed.
The summarizing structure is bound in size by
maintenance_work_mem
. In order to ensure that
there is no more than a 2% probability of failure to detect an
inconsistency for each heap tuple that should be represented in the
index, approximately 2 bytes of memory are needed per tuple. As
less memory is made available per tuple, the probability of missing
an inconsistency slowly increases. This approach limits the
overhead of verification significantly, while only slightly reducing
the probability of detecting a problem, especially for installations
where verification is treated as a routine maintenance task. Any
single absent or malformed tuple has a new opportunity to be
detected with each new verification attempt.
amcheck
Effectively
amcheck
can be effective at detecting various types of
failure modes that data page
checksums will always fail to catch. These include:
Structural inconsistencies caused by incorrect operator class implementations.
This includes issues caused by the comparison rules of operating
system collations changing. Comparisons of datums of a collatable
type like text
must be immutable (just as all
comparisons used for B-Tree index scans must be immutable), which
implies that operating system collation rules must never change.
Though rare, updates to operating system collation rules can
cause these issues. More commonly, an inconsistency in the
collation order between a master server and a standby server is
implicated, possibly because the major operating
system version in use is inconsistent. Such inconsistencies will
generally only arise on standby servers, and so can generally
only be detected on standby servers.
If a problem like this arises, it may not affect each individual index that is ordered using an affected collation, simply because indexed values might happen to have the same absolute ordering regardless of the behavioral inconsistency. See Section 23.1 and Section 23.2 for further details about how PostgreSQL uses operating system locales and collations.
Structural inconsistencies between indexes and the heap relations
that are indexed (when heapallindexed
verification is performed).
There is no cross-checking of indexes against their heap relation during normal operation. Symptoms of heap corruption can be subtle.
Corruption caused by hypothetical undiscovered bugs in the underlying PostgreSQL access method code, sort code, or transaction management code.
Automatic verification of the structural integrity of indexes
plays a role in the general testing of new or proposed
PostgreSQL features that could plausibly allow a
logical inconsistency to be introduced. Verification of table
structure and associated visibility and transaction status
information plays a similar role. One obvious testing strategy
is to call amcheck
functions continuously
when running the standard regression tests. See Section 32.1 for details on running the tests.
File system or storage subsystem faults where checksums happen to simply not be enabled.
Note that amcheck
examines a page as represented in some
shared memory buffer at the time of verification if there is only a
shared buffer hit when accessing the block. Consequently,
amcheck
does not necessarily examine data read from the
file system at the time of verification. Note that when checksums are
enabled, amcheck
may raise an error due to a checksum
failure when a corrupt block is read into a buffer.
Corruption caused by faulty RAM, or the broader memory subsystem.
PostgreSQL does not protect against correctable memory errors and it is assumed you will operate using RAM that uses industry standard Error Correcting Codes (ECC) or better protection. However, ECC memory is typically only immune to single-bit errors, and should not be assumed to provide absolute protection against failures that result in memory corruption.
When heapallindexed
verification is
performed, there is generally a greatly increased chance of
detecting single-bit errors, since strict binary equality is
tested, and the indexed attributes within the heap are tested.
In general, amcheck
can only prove the presence of
corruption; it cannot prove its absence.
No error concerning corruption raised by amcheck
should
ever be a false positive. amcheck
raises
errors in the event of conditions that, by definition, should never
happen, and so careful analysis of amcheck
errors is often required.
There is no general method of repairing problems that
amcheck
detects. An explanation for the root cause of
an invariant violation should be sought. pageinspect may play a useful role in diagnosing
corruption that amcheck
detects. A REINDEX
may not be effective in repairing corruption.


Spoiler Alert!
Question 1
It's not a bomb in the box, it's Gwyneth Paltrow's head.
Don't want to spoil it?
Skip to the next question.
The Island
The Village
The Game
The Sixt Sense
The Departed
Fight Club
Se7en
Titanic
Saving Private Ryan
Inside Out
Donnie Darko
Inglourious Basterds
The Orphan
Cast Away
Ex Machina
Memento
Inception
Saw
A Beautiful Mind
The Prestige
Seven Pounds
The Usual Suspects
Hostel
Pulp Fiction
Pearl Harbour
The Others
Gone Girl
Lost in Translation
Fargo
The Green Mile


This small village lies about 30nm east of Bodrum on the northern coast of the Gulf of Gokova. It is easily identified by the tall chimney of the power station.
Position 37° 1.42'N, 27° 59.6'E.
There is a new marina here due to open in May 2014.
The bay is too deep for anchoring and is subject to strong down gusts.
Last updated March 2014.


Pie charts are used to show part-to-whole relationships for a set of positive values. The angle (and thus the area) of each sector is proportional to the fraction of each value relative to the total.


Study part-time, three days a week, while maintaining your work schedule.
Learn Advanced Excel, Python, JavaScript (D3.js, Leaflet.js), HTML5/CSS, API Interactions, Social Media Mining, SQL, Tableau, Advanced Statistics, Machine Learning, R, Git/GitHub, and more.*


|
JavaTM 2 Platform Standard Ed. 5.0 |
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
public interface Comparator<T>
A comparison function, which imposes a total ordering on some collection of objects. Comparators can be passed to a sort method (such as Collections.sort) to allow precise control over the sort order. Comparators can also be used to control the order of certain data structures (such as TreeSet or TreeMap).
The ordering imposed by a Comparator c on a set of elements S is said to be consistent with equals if and only if (compare((Object)e1, (Object)e2)==0) has the same boolean value as e1.equals((Object)e2) for every e1 and e2 in S.
Caution should be exercised when using a comparator capable of imposing an ordering inconsistent with equals to order a sorted set (or sorted map). Suppose a sorted set (or sorted map) with an explicit Comparator c is used with elements (or keys) drawn from a set S. If the ordering imposed by c on S is inconsistent with equals, the sorted set (or sorted map) will behave "strangely." In particular the sorted set (or sorted map) will violate the general contract for set (or map), which is defined in terms of equals.
For example, if one adds two keys a and b such that (a.equals((Object)b) && c.compare((Object)a, (Object)b) != 0) to a sorted set with comparator c, the second add operation will return false (and the size of the sorted set will not increase) because a and b are equivalent from the sorted set's perspective.
Note: It is generally a good idea for comparators to implement java.io.Serializable, as they may be used as ordering methods in serializable data structures (like TreeSet, TreeMap). In order for the data structure to serialize successfully, the comparator (if provided) must implement Serializable.
For the mathematically inclined, the relation that defines the total order that a given comparator c imposes on a given set of objects S is:
{(x, y) such that c.compare((Object)x, (Object)y) <= 0}.The quotient for this total order is:
{(x, y) such that c.compare((Object)x, (Object)y) == 0}.It follows immediately from the contract for compare that the quotient is an equivalence relation on S, and that the natural ordering is a total order on S. When we say that the ordering imposed by c on S is consistent with equals, we mean that the quotient for the natural ordering is the equivalence relation defined by the objects' equals(Object) method(s):
{(x, y) such that x.equals((Object)y)}.
This interface is a member of the Java Collections Framework.
Comparable
,
Arrays.sort(Object[], Comparator)
,
TreeMap
,
TreeSet
,
SortedMap
,
SortedSet
,
Serializable
| Method Summary | |
|---|---|
int |
compare(T o1,
T o2)
Compares its two arguments for order. |
boolean |
equals(Object obj)
Indicates whether some other object is "equal to" this Comparator. |
| Method Detail |
|---|
int compare(T o1, T o2)
The implementor must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y. (This implies that compare(x, y) must throw an exception if and only if compare(y, x) throws an exception.)
The implementor must also ensure that the relation is transitive: ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.
Finally, the implementer must ensure that compare(x, y)==0 implies that sgn(compare(x, z))==sgn(compare(y, z)) for all z.
It is generally the case, but not strictly required that (compare(x, y)==0) == (x.equals(y)). Generally speaking, any comparator that violates this condition should clearly indicate this fact. The recommended language is "Note: this comparator imposes orderings that are inconsistent with equals."
o1
- the first object to be compared.o2
- the second object to be compared.
ClassCastException
- if the arguments' types prevent them from
being compared by this Comparator.boolean equals(Object obj)
comp1.equals(comp2)
implies that sgn(comp1.compare(o1,
o2))==sgn(comp2.compare(o1, o2)) for every object reference
o1 and o2.Note that it is always safe not to override Object.equals(Object). However, overriding this method may, in some cases, improve performance by allowing programs to determine that two distinct Comparators impose the same order.
equals
in class Object
obj
- the reference object with which to compare.
true
only if the specified object is also
a comparator and it imposes the same ordering as this
comparator.Object.equals(java.lang.Object)
,
Object.hashCode()
|
JavaTM 2 Platform Standard Ed. 5.0 |
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | |||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
Copyright © 2004, 2010 Oracle and/or its affiliates. All rights reserved. Use is subject to license terms. Also see the documentation redistribution policy.


ParticleSize()
语法
ParticleSize(#ParticleEmitter, Width, Height)概要
Change the particles dimensions. Particles are 2D planes (billboards) which always face the camera. All particles in an emitter always have the same size.
参数
#ParticleEmitter The particle emitter to use. Width, Size The new size of the particles, in world unit.
返回值
无.
已支持操作系统
所有


home
flights
hotels
cars
cruises
passports
visas
Iltwats Travel
upload a photo containing signage from any part of the world and let us translate it for you!
English
Chinese (simplified)
Chinese (traditional)
French
German
Italian
Japanese
Korean
Portugese
Spanish
×
Result
{% with messages = get_flashed_messages() %} {% if messages %} {% endif %} {% endwith %}


Warn points
Warn points allow for automatizing certain profiling tasks. With them, you can just let a program run, but stop automatically once the number of calls to a certain predicate (or the number of times a more complex control flow tree constellation has arisen) exceeds a predefined threshold. For example, you can define a number of calls to a certain predicate that you wouldn't expect your program to exceed, and if it does, this is indicatory of a problem. Moreover, the point at which execution is automatically halted because the threshold has been exceeded may indicate the part of execution where things go wrong, for example through infinite recursion.
The warn point system has been integrated with Kahina's BreakpointSystem. This allows to combine arbitrary tree patterns with thresholds, although in typical cases a one-node tree pattern will do. A warn point is a breakpoint paired with a threshold and a counter. The counter starts at 0 and is incremented every time there is a match. Unlike a breakpoint match, a warn point match has no visible effect until the counter hits the threshold. Then, the counter is reset to 0 and Kahina shows the usual breakpoint match behavior: if Kahina is in auto-complete or leap mode, it goes into stop mode, thereby pausing execution of the program. Additionally, a dialog opens indicating which warn point has matched.
Warn points are defined through the warn point editor. This editor is like the other breakpoint editors, except that it has an additional input field for specifiying the threshold.
TRALE example
Let's say your grammar contains the predicate tree_append/3 and you want to be warned if it is called 1000 times. You can define a warn point as follows:
- Click Warn points (call tree) in the Breakpoints menu. (Since we are only defining a one-node tree pattern, it does not matter if we choose the call or step tree.)
- Click New.
- In the Node constraint area, select step label and contains and enter tree_append/3.
- Enter a catchy Name for the warn point, such as 1000x tree_append/3.
- In the Warn after field, enter the threshold 1000.
- Click Apply and quit in the Profile window.
Now start the parse by clicking the leap (fast forward) button. After 1000 calls to tree_append/3, leaping stops and the following window appears:
Attachments (4)
- Prenzlgram-warn-edit.2.png (34.5 KB) - added by jd 8 years ago.
- Prenzlgram-warn-warn.2.png (7.2 KB) - added by jd 8 years ago.
- Prenzlgram-warn-edit.png (34.5 KB) - added by jd 8 years ago.
- Prenzlgram-warn-warn.png (7.2 KB) - added by jd 8 years ago.
Download all attachments as: .zip


a66
|
||||||
|
|
|
674
22 1000
Forms Designer The Forms Designer is the part of Power Objects used to build applications. The Forms Designer uses a drag-and-drop approach to allow you to drag tables from the tables window into the form design window, as shown in Figure 35.10.
Applications developed with the Power Objects Forms Designer are typically fairly optimized. Unfortunately, Oracle Power Objects does not give you a view into the SQL statements that will be used to execute your transactions. However, you can view the SQL statements by using some user properties and the EXEC SQL command within some objects. Reports Designer The Reports Designer is the part of Power Objects used to build graphical reports. The Reports Designer also uses a drag-and-drop approach to allow you to drag tables from the tables window into the report design window, as shown in Figure 35.11.
As with the Forms Designer, applications developed with the Power Objects Reports Designer are typically fairly optimized. Unfortunately, as with the Forms Designer, Oracle Power Objects does not give you a view into the SQL statements that will be used to execute your transactions. However, you can view the SQL statements by using some user properties and the EXEC SQL command within some objects. This is not nearly as easy to do as it is with some of the other tools described in this chapter. Classes Classes are a key part of Oracle Power Objects. By using classes, you can reuse many of the objects you develop. If you use classes to contain reusable objects like labels, when you change the class, all other objects that use that class change automatically. The Class design window also uses a drag-and-drop interface (see Figure 35.12). It is easy to create reusable classes very quickly. If you take the time to develop classes you can reuse, you can improve your efficiency in the long run.
Power Objects gives you the ability to put these classes in libraries that can easily be used by others. Simply create a library and drop your classes or objects into it.
Third-Party ToolsOf the third-party tools available on the market today, several of the most popular are PowerBuilder from Powersoft, Gupta SQLWindows, and Borland Delphi. The following sections describe these tools with an emphasis on how to get the most performance out of them. All these tools are excellent products; I make no judgment about which tools are better or which will better suit your purposes. That choice is up to you. Delphi from BorlandBorlands Delphi has grown in popularity over the last few years and is now one of the top-selling application development tools. Delphi is a graphical, drag-and-drop tool that is very easy to use and very powerful. Delphi comes with ODBC drivers; by adding the SQL Links native drivers, you can connect to SQL*Net directly. It is much more efficient to build native Oracle applications than it is to use ODBC. ODBC essentially takes the calls to it and translates them to SQL*Net calls, causing unnecessary overhead. Delphi consists of two main components: The forms developer is simply called Delphi, and the reports developer is called ReportSmith. Delphi Forms Developer As is true with the other tools described in this chapter, the SQL statements generated by Delphi are generally good. If you do need to alter the SQL statements to make them more efficient, you can do so easily. While in the forms editor, you can easily modify the SQL statement, as shown in Figure 35.13. To edit the SQL statement, follow these steps:
Once you open the String List Editor, you can modify and optimize the SQL statements that will be used in this application. Depending on the complexity of your application and the database, you may not have to change the automatically generated SQL statements. But the capability is there if, for example, you want to change the SQL statement to invoke a stored procedure or function. ReportSmithAs with the Delphi forms development tool, the SQL statements generated by ReportSmith are generally good. If you have to alter the SQL statements to become more efficient, you can do so easily. While in ReportSmith, you can easily modify the SQL statement as shown in Figure 35.15. With ReportSmith, you can alter the SQL statements while you design the report or afterwards. To edit the SQL statement, follow these steps.
Depending on the complexity of your report, you may want to modify the SQL statements or add hints that can be used by the Oracle optimizer. Depending on the complexity of your application and the database, it may not be necessary to change the automatically generated SQL statements. If necessary, however, you can change the SQL statement to invoke a stored procedure or function.
|
| 6fc |
|


fetchStudentInfo
Fetches student info such as name and a pair of year id and register id for all school years available for this student.
Parameters
session: ISession - session tokens
Returns
Promise<IStudentInfo>


{% extends "_post.html" %}
{% hyde
title: "The Caves of Clojure: Part 1"
snip: "Getting a Roguelike up and running."
created: 2012-07-07 17:00:00
flattr: true
%}
{% block article %}
Lately I've had an urge to start playing a few games again, namely [Nethack][]
and [Dwarf Fortress][] (the latter being triggered by [this book][df-book]).
Aside from being incredibly fun, they also made me want to play around with
writing a [roguelike][] game of my own.
[Nethack]: http://www.nethack.org/
[Dwarf Fortress]: http://www.bay12games.com/dwarves/
[df-book]: http://www.amazon.com/gp/product/1449314945/ref=as_li_ss_tl?ie=UTF8&camp=1789&creative=390957&creativeASIN=1449314945&linkCode=as2&tag=stelos-20
[roguelike]: https://en.wikipedia.org/wiki/Roguelike
I could write them in Python, but lately I've been falling out of love with the
language. It's a solid workhorse that's not exciting or beautiful to me at all
any more. My affection has shifted more toward Clojure. Despite its Rubyesque
culture of brokenness, rampant lack of documentation, and warty JVM interop it's
still a wonderful language that's captured me (for now).
I've had the idea of writing a few roguelike games for a while, but the other
day I stumbled on [Trystan Spangler's blog][trystan] and his [series of
articles][trystan-tut] that walk through writing a roguelike game in Java.
[trystan]: http://trystans.blogspot.com/
[trystan-tut]: http://trystans.blogspot.com/2011/08/roguelike-tutorial-01-java-eclipse.html
I'm going to do a series of blog posts, each corresponding roughly to one of
Trystan's posts, as I work my way through writing a roguelike in Clojure. I may
or may not get all of the way through his twenty-post series. We'll see.
I'll assume you know Clojure during this series and won't be explaining every
single thing.
If you want to follow along, the code for this series is [on Bitbucket][bb] and
[on GitHub][gh]. There are tags like `entry-01` in the repo which you can
update to and see the code as it stood at the end of that entry.
[bb]: http://bitbucket.org/sjl/caves/
[gh]: http://github.com/sjl/caves/
Let's jump in. This entry corresponds to [post one in Trystan's
tutorial][trystan-tut].
[TOC]
Summary
-------
The first thing to do is to bootstrap an environment for development. I'll be
using Clojure 1.4, Leiningen 2, and [clojure-lanterna][] 0.9.0.
Trystan used Eclipse but I'll be using Vim and my fork of SLIMV.
[clojure-lanterna]: http://sjl.bitbucket.org/clojure-lanterna/
project.clj
-----------
I'm starting with a fairly simple `project.clj` file:
:::clojure
(defproject caves "0.1.0-SNAPSHOT"
:description "The Caves of Clojure"
:url "http://stevelosh.com/blog/2012/07/caves-of-clojure-01/"
:license {:name "MIT/X11"}
:dependencies [[org.clojure/clojure "1.4.0"]
[clojure-lanterna "0.9.0"]]
:main caves.core)
Nothing particularly crazy here.
clojure-lanterna
----------------
Trystan used his own library called AsciiPanel to handle the drawing of
characters to the screen. I'm going to use my own library [clojure-lanterna][],
which is a wrapper around the [Lanterna][] Java library.
I chose Lanterna because it supports drawing to a Swing-based "terminal" and to
the actual console. But unlike some other libraries, it doesn't actually link
against native code (it's pure Java) so it's more portable.
Being able to output to either a console or a GUI means that I can develop
through Swank really easily with the Swing terminal, but actuall play the
finished product in a terminal like God intended.
[Lanterna]: https://code.google.com/p/lanterna/
core.clj
--------
The full `core.clj` file I came up with was this:
:::clojure
(ns caves.core
(:require [lanterna.screen :as s]))
(defn main [screen-type]
(let [screen (s/get-screen screen-type)]
(s/in-screen screen
(s/put-string screen 0 0 "Welcome to the Caves of Clojure!")
(s/put-string screen 0 1 "Press any key to exit...")
(s/redraw screen)
(s/get-key-blocking screen))))
(defn -main [& args]
(let [args (set args)
screen-type (cond
(args ":swing") :swing
(args ":text") :text
:else :auto)]
(main screen-type)))
We're very much just bootstrapping things for now. The `-main` function parses
the command line arguments to figure out what type of terminal we should use,
and then passes that along to `main`.
For now, `main` simply:
* Gets an appropriately-typed terminal.
* Outputs a simple message.
* Redraws the screen (clojure-lanterna's screen layer buffers output until you
tell it to redraw).
* Waits for the user to press a key.
* Exits.
I chose to split the meat of the setup into a `main` function instead of just
putting everything in `-main` because that will make it easy for me to work
through Swank instead of the command line as we'll see in a moment.
Running
-------
There are two main ways to actually make this thing work.
First, we can run it as a standalone program with `lein trampoline run` at the
command line. I can pass a parameter to specify what type of terminal to use,
like `lein trampoline run :swing`.
We can also run it from a REPL, or a SLIME/Swank environment by simply
evaluating `(main :swing)` in the namespace. This is why I split out everything
but the command line argument parsing into a separate function.
Either way, once you run it you get something like this:
![Screenshot](/media/images{{ parent_url }}/caves-01-01.png)
This is the Swing terminal which I happened to start from swank. Press a key
and it will go away.
It doesn't look like much, but it's a [black triangle][]. In the next entry
we'll start doing more interesting things.
[black triangle]: http://rampantgames.com/blog/2004/10/black-triangle.html
{% endblock article %}


Weigh eight pounds but take up a full-size bed scratch at the door scratch at the door then walk away yet meow to be let in give me attention or face the wrath of my claws.
Weigh eight pounds but take up a full-size bed scratch at the door scratch at the door then walk away yet meow to be let in give me attention or face the wrath of my claws.
Weigh eight pounds but take up a full-size bed scratch at the door scratch at the door then walk away yet meow to be let in give me attention or face the wrath of my claws.


/**
* Stores the list of buffered ICE candidates received
* before RTCPeerConnection.setRemoteDescription is
* called. Adding ICE candidates before receiving the remote
* session description causes an ICE connection failures in a
* number of instances.
* @attribute _peerCandidatesQueue
* @param {Array} (#peerId) The Peer ID associated with the
* list of buffered ICE candidates.
* @param {Object} (#peerId).(#index) The buffered RTCIceCandidate
* object associated with the Peer.
* @type JSON
* @private
* @required
* @since 0.5.1
* @component ICE
* @for Skylink
*/
Skylink.prototype._peerCandidatesQueue = {};
/**
* Stores the list of flags associated to the PeerConnections
* to disable trickle ICE as attempting to establish an
* ICE connection failed after many trickle ICE connection
* attempts. To ensure the stability and increase the chances
* of a successful ICE connection, track the Peer connection and store
* it as a flag in this list to disable trickling of ICE connections.
* @attribute _peerIceTrickleDisabled
* @param {Boolean} (#peerId) The Peer trickle ICE disabled flag.
* If value is true, it means that trickling of ICE is
* disabled for subsequent connection attempt.
* @type JSON
* @private
* @required
* @since 0.5.8
* @component ICE
* @for Skylink
*/
Skylink.prototype._peerIceTrickleDisabled = {};
/**
* The list of Peer connection ICE candidate generation states that Skylink would trigger.
* - These states references the [w3c WebRTC Specification Draft](http://www.w3.org/TR/webrtc/#idl-def-RTCIceGatheringState).
* @attribute CANDIDATE_GENERATION_STATE
* @type JSON
* @param {String} NEW Value "new"
* The state when the object was just created, and no networking has occurred yet.

* This state occurs when Peer connection has just been initialised.
* @param {String} GATHERING Value "gathering"
* The state when the ICE engine is in the process of gathering candidates for connection.

* This state occurs after NEW state.
* @param {String} COMPLETED Value "completed"
* The ICE engine has completed gathering. Events such as adding a
* new interface or a new TURN server will cause the state to go back to gathering.

* This state occurs after GATHERING state and means ICE gathering has been done.
* @readOnly
* @since 0.4.1
* @component ICE
* @for Skylink
*/
Skylink.prototype.CANDIDATE_GENERATION_STATE = {
NEW: 'new',
GATHERING: 'gathering',
COMPLETED: 'completed'
};
/**
* Handles the ICE candidate object received from associated Peer connection
* to send the ICE candidate object or wait for all gathering to complete
* before sending the candidate to prevent trickle ICE.
* @method _onIceCandidate
* @param {String} targetMid The Peer ID associated with the ICE
* candidate object received.
* @param {Event} event The event object received in the RTCPeerConnection.
* onicecandidate to parse the ICE candidate and determine
* if gathering has completed.
* @trigger candidateGenerationState
* @private
* @since 0.1.0
* @component ICE
* @for Skylink
*/
Skylink.prototype._onIceCandidate = function(targetMid, event) {
if (event.candidate) {
if (this._enableIceTrickle && !this._peerIceTrickleDisabled[targetMid]) {
var messageCan = event.candidate.candidate.split(' ');
var candidateType = messageCan[7];
log.debug([targetMid, 'RTCIceCandidate', null, 'Created and sending ' +
candidateType + ' candidate:'], event);
this._sendChannelMessage({
type: this._SIG_MESSAGE_TYPE.CANDIDATE,
label: event.candidate.sdpMLineIndex,
id: event.candidate.sdpMid,
candidate: event.candidate.candidate,
mid: this._user.sid,
target: targetMid,
rid: this._room.id
});
}
} else {
log.debug([targetMid, 'RTCIceCandidate', null, 'End of gathering']);
this._trigger('candidateGenerationState', this.CANDIDATE_GENERATION_STATE.COMPLETED,
targetMid);
// Disable Ice trickle option
if (!this._enableIceTrickle || this._peerIceTrickleDisabled[targetMid]) {
var sessionDescription = this._peerConnections[targetMid].localDescription;
this._sendChannelMessage({
type: sessionDescription.type,
sdp: sessionDescription.sdp,
mid: this._user.sid,
agent: window.webrtcDetectedBrowser,
target: targetMid,
rid: this._room.id
});
}
}
};
/**
* Buffers an ICE candidate object associated with a Peer connection
* to prevent disruption to ICE connection when ICE candidate
* is received before RTCPeerConnection.setRemoteDescription
* is called.
* @method _addIceCandidateToQueue
* @param {String} targetMid The Peer ID associated with the ICE
* candidate object.
* @param {Object} candidate The constructed ICE candidate object.
* @private
* @since 0.5.2
* @component ICE
* @for Skylink
*/
Skylink.prototype._addIceCandidateToQueue = function(targetMid, candidate) {
log.debug([targetMid, null, null, 'Queued candidate to add after ' +
'setRemoteDescription'], candidate);
this._peerCandidatesQueue[targetMid] =
this._peerCandidatesQueue[targetMid] || [];
this._peerCandidatesQueue[targetMid].push(candidate);
};
/**
* Handles the event when adding an ICE candidate has been added
* successfully. This is mainly to prevent JShint errors.
* @method _onAddIceCandidateSuccess
* @private
* @since 0.5.9
* @component ICE
* @for Skylink
*/
Skylink.prototype._onAddIceCandidateSuccess = function () {
log.debug([null, 'RTCICECandidate', null, 'Successfully added ICE candidate']);
};
/**
* Handles the event when adding an ICE candidate has failed.
* This is mainly to prevent JShint errors.
* @method _onAddIceCandidateFailure
* @param {Object} error The error received in the failure callback
* in RTCPeerConnection.addIceCandidate(candidate, successCb, failureCb).
* @private
* @since 0.5.9
* @component ICE
* @for Skylink
*/
Skylink.prototype._onAddIceCandidateFailure = function (error) {
log.error([null, 'RTCICECandidate', null, 'Error'], error);
};
/**
* Adds the list of ICE candidates bufferred before RTCPeerConnection.setRemoteDescription
*  is called associated with the Peer connection.
* @method _addIceCandidateFromQueue
* @param {String} targetMid The Peer ID to add the associated bufferred
* ICE candidates.
* @private
* @since 0.5.2
* @component ICE
* @for Skylink
*/
Skylink.prototype._addIceCandidateFromQueue = function(targetMid) {
this._peerCandidatesQueue[targetMid] =
this._peerCandidatesQueue[targetMid] || [];
if(this._peerCandidatesQueue[targetMid].length > 0) {
for (var i = 0; i < this._peerCandidatesQueue[targetMid].length; i++) {
var candidate = this._peerCandidatesQueue[targetMid][i];
log.debug([targetMid, null, null, 'Added queued candidate'], candidate);
this._peerConnections[targetMid].addIceCandidate(candidate,
this._onAddIceCandidateSuccess, this._onAddIceCandidateFailure);
}
delete this._peerCandidatesQueue[targetMid];
} else {
log.log([targetMid, null, null, 'No queued candidates to add']);
}
};