© 2017 The original authors.
|
Note
|
Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically. |
1. Lab Setup
1.1. Prerequisites
You need an installed JDK, at least Java 8. If you use Git, then you can checkout the Code using Git. You can also download the initial code or complete code directly.
An installed IDE is recommended but not necessary. Having cURL
, a browser or, any other sophisticated HTTP client installed is beneficial for issuing HTTP requests.
1.2. Register a GitHub account (Optional, recommended)
Go to https://github.com and signup for a free account. If you already have a GitHub account, you can skip this step.
1.3. Clone the Git repository
Clone the Reactive Coding Workshop with Spring Boot project using Git.
Console
Open a console and type the following command to clone the project:
$ git clone https://github.com/mp911de/reactive-coding-workshop.git
Eclipse or STS
-
From the project explorer, right click,
Import
,Git
,Projects from Git
. -
Select
Clone URI
and clickNext
. -
Enter the URI https://github.com/mp911de/reactive-coding-workshop.git and click
Next
. -
Select the master branch and click
Next
The projects will be imported.
|
Note
|
Note that depending on the version of Eclipse / STS, your version of Java, and other factors, you may encounter errors. These will need to be fixed on a case-by-case basis before proceeding. |
IntelliJ IDEA
-
From the menu bar
VCS
, selectCheckout from Version Control
,Github
. -
Enter the URI https://github.com/mp911de/reactive-coding-workshop.git and click
Clone
. -
The repository will be cloned.
1.4. IDE Import
1.5. Eclipse or STS
-
From the project explorer, right click,
Import
,Maven
,Existing Maven Projects
. -
Navigate to the folder where you cloned the repository and
Finish
. -
The projects will be imported.
Eclipse users wanting to use Lombok need to install the Eclipse/Lombok plugin.
Run lombok.jar
as a java app (i.e. double-click it, usually) to install. Also, add lombok.jar
to your project. Supported variants: SpringSource Tool Suite, JBoss Developer Studio
|
Note
|
Note that depending on the version of Eclipse / STS, your version of Java, and other factors, you may encounter errors. These will need to be fixed on a case-by-case basis before proceeding. |
1.6. IntelliJ IDEA
-
From the
File
menu selectImport Project
and navigate to wherever the course labs were installed during the previous step. -
Click
Import project from external model
and import as Maven projects. -
After clicking
Next
, select theSearch for projects recursively
checkbox. -
Click
Next
again and several projects should be listed. -
Click
Next
and select a suitable SDK. -
Click
Next
one last time. You can leave the project name and location. Click Finish.
IntelliJ IDEA users wanting to use Lombok need to install the Eclipse/Lombok plugin. A plugin developed by Michael Plushnikov adds support for most features.
Congratulations! You have setup everything you will need for the rest of the course. The hard part is over!
2. Runnable Application
About this Lab
You will learn how to start a reactive Spring Boot application
Prerequisites
To complete these steps, you will need:
-
The code checked out.
-
Optional: The code imported into your IDE.
Estimated Duration
5 minutes
Steps
-
The project contains a runnable application.
-
IDE: Navigate to the main class
ReactiveCodingWorkshopApplication
. Run this main class. The application will boot up and start a web server on port8080
. -
Maven users: Open a console and navigate to the code directory. Run
./mvnw spring-boot:run
-
-
Navigate in your browser to the following endpoint: http://localhost:8080/
You should see something like:
When you are done, stop the application.
Congratulations, you have finished this exercise.
3. Get Comfortable with the Code
About this Lab
You will walk through the code to get familiar with the individual bits.
Prerequisites
To complete these steps, you will need:
-
The code checked out.
-
Optional: The code imported into your IDE.
Estimated Duration
15 minutes
Steps
-
Go to the package
org.dogepool.reactiveboot.config
. It contains the configuration classes to provide properties to the application andWebConfig
to configure FreeMarker for view template resolution. -
Go to the package
org.dogepool.reactiveboot.domain
. This package contains the domain model:UserStat
andUser
with an embeddedUserProfile
.UserStat
andUser
are aggregate roots.UserStatRepository
andUserRepository
interact with the domain objects. -
org.dogepool.reactiveboot.view.model
containsMinerModel
that is used to populate the view. -
Now, go to
org.dogepool.reactiveboot.controller
. This package contains the controller classes that are exposed by Spring WebFlux as reactive HTTP endpoints. -
Take a look at
org.dogepool.reactiveboot
. You will noticeDataInitializer
. Why is this class usingMongoTemplate
? I thought the workshop title said reactive coding? You’re right! This class uses a blockingMongoTemplate
inside a@PostConstruct
method to load data into MongoDB. This code happens during initialization and there’s not need to go async. As of now, you should not use reactive infrastructure because that performs work on other threads than the main thread while we’re still in the initialization phase. Initialization means that Spring Framework holds some exclusive object locks that may cause locks which do not resolve (similar to a deadlock) therefore the only safe approach is using plain old blocking I/O. MongoDB is started as embedded process. And to be honest: You don’t want to mess with reactive synchronization.
|
Note
|
Repositories are implemented by Spring Data MongoDB. Domain classes use Lombok annotations to get rid of boilerplate code. Getter/Setter/Constructors and more are generated during runtime by the annotation processor. |
|
Note
|
Did you notice that src/test/java contains a bunch of JUnit tests? These tests will guide you in the next steps towards the implementation and help to verify whether your implementation is correct. Don’t worry, at this stage, the tests do not pass.
|
Congratulations, you have finished this exercise.
4. First Steps with Mono
and Flux
About this Lab
You will learn about Mono
and Flux
and their role as elementary reactive types. You will see how to create instances, compose a reactive sequence by applying operators and how to consume data.
Prerequisites
To complete these steps, you will need:
-
The code checked out.
-
The code imported into your IDE.
Estimated Duration
25 minutes
Mono
and Flux
are reactive types that emit 0..1
values and 0..1..N
values, respectively. They can be created as scalar values to just emit the provided value, from a Callable
or as generator to provide a sink for processes that publish data to a target.
Steps
-
Go to
src/test/java
org.dogepool.reactiveboot.GettingStartedTests
. There you find a couple of methods withTODO
comments. Read each method’s TODO description and solve the tasks. -
monoShouldCreateScalarValue
: ScalarMono
instances are created with theMono.just(…)
factory method. ReplaceMono.empty()
withMono.just("Hello, World")
. -
monoShouldMapValueToHelloWorld
: Values can be mapped using themap
operators. Map the emitted valueHello
toHello, World
usingmono = mono.map(s → String.format("%s, World", s));
. -
monoShouldFlatMapValueToHelloWorld
:map
is perfect to map a non-null value into another non-null value calling code that is likely not to block. However, some cases require further I/O or can lead to absence of values, or, the emission of many values.Mono.then(…)
is the flap-map operator for this case. Apply it withmono.then(s → Mono.just(String.format("%s, World", s)));
. -
monoShouldDeferCallable
: You can create aMono
from aCallable
to obtain a value applying reactive execution. Create aMono
from aCallable
withMono.fromCallable(myValue)
. AMono
can be created from other sources, like the first element in anIterable
, otherMono
s, aSupplier
, aCompletableFuture
and many more. -
monoShouldExecuteOnADifferentThread
: Until now, all operations ran on the same thread..subscribe()
on each invocation subscribed to theMono
and initiated execution. Because it’s the same thread, you didn’t run into background execution. Use aScheduler
to subscribe and publish elements on a different thread with ` mono.subscribeOn(elastic).publishOn(elastic)`. -
It’s likely that you don’t see any output at all. This is, because subscription and execution are now separate threads. You don’t await execution. You can block the calling thread to synchronize the result by appending
.block()
to.subscribe()
. The method will wait up to 30 seconds for the result. Calling.block
is a last resort if no other synchronization is possible. In general, avoid.block()
because calling.block()
in a code block that should be non-blocking, will enforce blocking whereas your intention in non-blocking programming is not to block non-blocking execution. -
fluxShouldCreateScalarValues
: Let’s look atFlux
.Flux
is the type to emit multiple elements. Create a scalarFlux
that emitsHello
andWorld
items with theFlux.just(…)
factory method. ReplaceFlux.empty()
withFlux.just("Hello", "World")
. -
fluxShouldCreateHelloWorldFromIterable
: You can createFlux
from various sources. A handy approach to use resolvedIterable
s of data (such as aList
orSet
) in a reactive flow is creating aFlux
from anIterable
withFlux.fromIterable(…)
. ReplaceFlux.empty()
withFlux.fromIterable(strings)
. -
fluxShouldConcatTwoMonos
: A common scenario in reactive programming is combination of multiple reactive types without enforcing synchronization. This step provides twoMono
s (which are aPublisher
each) and they should be concatenated. Concat retains the order in which thePublisher
emits its values. Use theFlux.concat(…)
factory method by invokingFlux.concat(hello, world)
. Another approach is using themerge
operator. Emitted items from aPublisher
merged with.merge(…)
may interleave with other items. -
monoShouldEmitIndividualCharactersAsString
: A reactive sequence converts emitted elements by usingmap
operator. A single element is accepted and a single converted (mapped) element is emitted – one in, one out. You might run into a scenario in which you require emission of many elements of one input element. Just think of accessing a data source. Accessing data can return multiple objects based on the query. For this case, apply theflatMap
operator. The function applied withflatMap
takes the original string and should emit each letter asString
. You can use a neat reg-ex trick:Flux.fromArray(s.split("|")
. So replaceFlux.empty()
withmono.flatMap(s → Flux.fromArray(s.split("")))
. Alternatively, did you know about the char stream fromString
? You can use it withFlux.fromStream(s.chars().mapToObj(value → String.valueOfchar) value)
.
Your code could look like:
public class GettingStartedTests {
@Test
public void monoShouldCreateScalarValue() {
Mono<String> mono = Mono.just("Hello, World");
mono.subscribe(s -> System.out.println(s));
}
@Test
public void monoShouldMapValueToHelloWorld() {
Mono<String> mono = Mono.just("Hello");
mono = mono.map(s -> String.format("%s, World", s));
mono.subscribe(System.out::println);
}
@Test
public void monoShouldFlatMapValueToHelloWorld() {
Mono<String> mono = Mono.just("Hello");
mono = mono.then(s -> Mono.just(String.format("%s, World", s)));
mono.subscribe(System.out::println);
}
@Test
public void monoShouldDeferCallable() {
Callable<String> myValue = () -> "Hello, World";
Mono<String> mono = Mono.fromCallable(myValue);
mono.subscribe(System.out::println);
}
@Test
public void monoShouldExecuteOnADifferentThread() {
Scheduler elastic = Schedulers.elastic();
Mono<String> mono = Mono.just("Hello, World");
mono = mono.subscribeOn(elastic).publishOn(elastic);
mono.doOnNext(s -> System.out.println(s)).subscribe().block();
}
@Test
public void fluxShouldCreateScalarValues() {
Flux<String> flux = Flux.just("Hello", "World");
flux.subscribe(System.out::println);
}
@Test
public void fluxShouldCreateHelloWorldFromIterable() {
List<String> strings = Arrays.asList("Hello", "World");
Flux<String> flux = Flux.fromIterable(strings);
flux.subscribe(System.out::println);
}
@Test
public void fluxShouldConcatTwoMonos() {
Mono<String> hello = Mono.just("Hello");
Mono<String> world = Mono.just("World");
Flux<String> flux = Flux.concat(hello, world);
flux.subscribe(System.out::println);
}
@Test
public void monoShouldEmitIndividualCharactersAsString() {
Mono<String> mono = Mono.just("Hello, World");
Flux<String> flux = mono.map(s -> s.split("")).flatMap(Flux::fromArray);
flux.subscribe(System.out::println);
}
}
Congratulations, you have finished this exercise. Several factory methods such as concat
and merge
are also available on instances.
5. Reactive Data Access
About this Lab
You will learn how to use reactive MongoDB repositories and how to create reactive repository query methods.
Prerequisites
To complete these steps, you will need:
-
The code checked out.
-
The code imported into your IDE.
Estimated Duration
10 minutes
Creating repository query methods
Reactive query methods work pretty much the same as blocking repository query methods. Spring Data identifies reactive repositories by the use of reactive types in method signatures. Declaring a repository that extends ReactiveCrudRepository
will inherit all declared methods and Spring Data will implement that repository using reactive infrastructure. Reactive repositories must use reactive result types, methods can accept reactive types (Mono
, Flux
) or resolved parameters (String
, int
, …).
Spring Data executes either a single element query or a collection query based on the return type characteristics. Mono
leads to a single element query, Flux
can return many elements.
IndexController
The IndexController
populates a Model
and returns view name for the web application.
Steps
-
Go to
IndexController
. The code contains threeTODO
s. Focus only on the upper twoTODO
s providing values forhashLadder
andcoinsLadder
attributes. -
hashLadder
contains the top-10 users ordered by their hash rate, highest first. Stats regarding the hashrate are stored inUserStat
and can be accessed throughUserStatRepository
. -
Go to
UserStatRepository
and create a reactive repository query method to return the top 10UserStat
objects ordered byhashrate
(descending). The method would be namedfindTop10ByOrderByHashrateDesc
. -
coinsLadder
inIndexController
contains the top-10 users ordered by their mined coins, highest first. Stats regarding the mined coins are stored inUserStat
and can be accessed throughUserStatRepository
. -
Go to
UserStatRepository
and create a reactive repository query method to return the top 10UserStat
objects ordered bytotalCoinsMined
(descending). The method would be namedfindTop10ByOrderByTotalCoinsMinedDesc
. -
Now go back to
IndexController
and wire the repository query methods to the model attributes. Spring WebFlux accepts reactive types in theModel
.
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
@RequiredArgsConstructor
@Controller
public class IndexController {
UserStatRepository userStatRepository;
DogeProperties dogeProperties;
@GetMapping("/")
String getIndex(Model model) {
model.addAttribute("poolName", dogeProperties.getPoolName());
model.addAttribute("hashLadder",
userStatRepository.findTop10ByOrderByHashrateDesc());
model.addAttribute("coinsLadder",
userStatRepository.findTop10ByOrderByTotalCoinsMinedDesc());
// TODO: Calculate the overall gigaHashrate and miningUserCount taking
// a reactive approach
model.addAttribute("gigaHashrate", -1d);
model.addAttribute("miningUserCount", -1);
return "index";
}
}
public interface UserStatRepository extends ReactiveCrudRepository<UserStat, ObjectId> {
Flux<UserStat> findTop10ByOrderByHashrateDesc();
Flux<UserStat> findTop10ByOrderByTotalCoinsMinedDesc();
}
Congratulations, you have finished this exercise.
Bonus
-
Run
IndexControllerIntegrationTests
to verify that 3 of 4 tests pass.IndexControllerIntegrationTests.indexModelShouldProvideModelAttributes
fails because Step 6 is not completed yet. -
Start now the application again. You will notice the start page has changed.
Bonus
-
Did you notice the
Hashrate greater
filter? And did you notice, there’s no code yet to handle the filtering? Do you want to fix that issue? -
Extend
IndexController
to take a non-mandatory numeric request parameterhashFilter
and filter the two streams whereUserStats#Hashrate
is greaterhashFilter
. How many approaches can you find to do so? -
The
input
element should retain the previously entered value. Can you figure out how to do so by changingModel
contents andindex.ftl
? -
Start now the application again and check whether your changes have been successful.
-
You will notice that the subsequent code samples in the lab docs do not contain code to solve this bonus.
6. Reactive Computations
About this Lab
In this lab you’ll learn how to apply statistic computation in a deferred flow.
Prerequisites
To complete these steps, you will need:
-
Step 5, Reactive Data Access completed
Estimated Duration
15 minutes
Missing Bits on the Index Page
The index page shows -1
for gigaHashrate
and miningUserCount
. Both values require statistical computation based on the data in UserStat
. That’s a sum of all hash rates and the user count. Spring WebFlux synchronizes computation of reactive types first before the actual model evaluation. That behavior allows setting values in a reactive flow. The computation in this lab should remain non-blocking and take advantage of the callback methods provided by the reactive types.
This lab has multiple valid solutions.
Steps
-
Go to
IndexController
and implement a computation to provide values forgigaHashrate
andminingUserCount
. -
Flux
provides callback methods for functions invoked on each published element. Expect the callback to happen on a different thread, maybe even callbacks by multiple threads at the same time. The attributesgigaHashrate
andminingUserCount
summarize the number of users and the hash rate. Did you useAtomicLong
/AtomicInteger
already? Both types are atomic counters for lock-free counting. CreateAtomicLong hashrate
andAtomicInteger users
variables and increment the values by applying a function with thedoOnNext
operator. -
The actual model values can be set on
Flux
completion. Set the model attributes by applying a function with thedoOnComplete
operator. -
Spring WebFlux requires the
Flux
in the model to synchronize execution. Add theFlux
to theModel
, the attribute name has no significance and can be anyString
. -
Start now the application again. You will notice the start page has changed.
Your code could look like:
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
@RequiredArgsConstructor
@Controller
public class IndexController {
UserStatRepository userStatRepository;
DogeProperties dogeProperties;
@GetMapping("/")
String getIndex(Model model) {
model.addAttribute("poolName", dogeProperties.getPoolName());
model.addAttribute("hashLadder",
userStatRepository.findTop10ByOrderByHashrateDesc());
model.addAttribute("coinsLadder",
userStatRepository.findTop10ByOrderByTotalCoinsMinedDesc());
AtomicLong hashrate = new AtomicLong();
AtomicInteger users = new AtomicInteger();
Flux<UserStat> userStatFlux = userStatRepository.findAll()
.doOnNext(userStat -> hashrate.addAndGet((long) userStat.getHashrate()))
.doOnNext(userStat -> users.incrementAndGet()).doOnComplete(() -> {
model.addAttribute("gigaHashrate", hashrate.doubleValue());
model.addAttribute("miningUserCount", users.get());
});
model.addAttribute("userStatFlux", userStatFlux);
return "index";
}
}
Congratulations, you have finished this exercise.
Bonus
-
Run
IndexControllerIntegrationTests
to verify that all tests pass.
7. Miner Detail Page
About this Lab
You will learn how to combine objects emitted from multiple publishers and combined to create a composite result with reactive types.
Prerequisites
To complete these steps, you will need:
-
Step 5, Reactive Data Access completed
Estimated Duration
10 minutes
Miner Page
The miner detail page shows details about the miner along with some stats. The miner details are available through User
, stats from UserStat
. UserStat.id
is not the user id but a database-specific identifier. That’s why UserStatRepository
requires a new repository query method to look up UserStat
by user id.
Steps
-
Go to
UserStatRepository
and add a new repository query method to look upUserStat
byUserId
returning a single element. -
Go to
MinerController
and fetchUser
fromUserRepository
andUserStat
fromUserStatRepository
. Combine the publishers to a tuple and map the resultingUser
andUserStat
objects intoMinerModel
withMinerModel.of(…)
. -
Start now the application again. Click on a miner once the page has loaded.
Your code could look like:
@Controller
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
@RequiredArgsConstructor
public class MinerController {
UserRepository userRepository;
UserStatRepository userStatRepository;
@GetMapping("/miner/{id}")
String getMiner(@PathVariable String id, Model model) {
Mono<MinerModel> compositeModel = userRepository.findOne(id)
.and(user -> userStatRepository.findByUserId(user.getId()))
.map(tuple -> MinerModel.of(tuple.getT1(), tuple.getT2()));
model.addAttribute("model", compositeModel);
return "miner";
}
}
Congratulations, you have finished this exercise.
Bonus
These are bonus steps explaining advanced reactive programming model patterns.
1. Rank on Miner Detail Page
About this Lab
You will learn how to apply stream processing for long-running tasks that process potentially huge data sets.
Prerequisites
To complete these steps, you will need:
-
Step 5, Reactive Data Access completed
-
Step 7, Miner Detail Page completed
Miner Page
The miner detail page shows ranking by coins and by hash rate. These values derive from the state of the system, in particular the coins and hash rates of all users. These details aren’t something that is computed on the fly but rather refreshed in certain intervals. For this workshop, we can use Spring WebFlux to trigger processing because we don’t want to establish a complex scheduling infrastructure.
Maintenance Job: CalculateRanks
The goal is to create a maintenance job that can be started any time and that processes the whole user base, updating UserStat
ranks.
Steps
-
Create a new package
org.dogepool.reactiveboot.service
with a new@Component
class namedCalculateRanks
. -
Use
ReactiveMongoTemplate
to iterate overUserStat
. Using a MongoDB query with the appropriate sort order helps to retrieve results in the order of ranking. Make sure that results are published on a single thread (seeSchedulers.single()
). Using two distinct reactive flows might be the simpler approach than a combined attempt to calculate both ranks in a single pass. -
Use
flatMap(…)
and anAtomicLong
counter to increment the rank counter. UpdateUserStat
selectively by setting just the rank property. -
Repeat for the other rank property.
-
Synchronize both
Flux
withFlux.merge(…)
returning the.count()
. -
Go to
MaintenanceController
and wire the dependency toCalculateRanks
. Call the method to recalculate the ranks. -
Invoke the maintenance job with
cURL
or your browser. -
Start now the application again. Click on a miner once the page has loaded.
curl -X POST http://localhost:8080/maintenance/ranks
Your code could look like:
@RestController
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
@RequiredArgsConstructor
public class MaintenanceController {
CalculateRanks calculateRanks;
@PostMapping("maintenance/ranks")
public Mono<Long> recalculateRanks() {
return calculateRanks.recalculateRanks();
}
}
@Component
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
@RequiredArgsConstructor
public class CalculateRanks {
ReactiveMongoTemplate mongoTemplate;
public Mono<Long> recalculateRanks() {
return Flux.merge(updateRankByHash(), updateRankByCoins()).count();
}
private Flux<UpdateResult> updateRankByCoins() {
Query query = new Query().with(new Sort(Direction.DESC, "totalCoinsMined"));
AtomicLong atomicLong = new AtomicLong();
return mongoTemplate
.find(query, UserStat.class)
.publishOn(Schedulers.single())
.flatMap(
userStat -> {
long rank = atomicLong.incrementAndGet();
Query userStatQuery = new Query(Criteria.where("id").is(
userStat.getId()));
return mongoTemplate.updateFirst(userStatQuery,
new Update().set("rankByCoins", rank), UserStat.class);
});
}
private Flux<UpdateResult> updateRankByHash() {
Query query = new Query().with(new Sort(Direction.DESC, "hashrate"));
AtomicLong atomicLong = new AtomicLong();
return mongoTemplate
.find(query, UserStat.class)
.publishOn(Schedulers.single())
.flatMap(
userStat -> {
long rank = atomicLong.incrementAndGet();
Query userStatQuery = new Query(Criteria.where("id").is(
userStat.getId()));
return mongoTemplate.updateFirst(userStatQuery,
new Update().set("rankByHash", rank), UserStat.class);
});
}
}
Congratulations, you have finished this exercise.
2. Reactive Micro-Proxy
About this Lab
You will learn how to use Spring 5’s functional WebClient
to set up a reactive microproxy.
Prerequisites
To complete these steps, you will need:
-
Step 5, Reactive Data Access completed
-
Step 7, Miner Detail Page completed
Miner Page
Did you notice the avatar image source? It points to https://randomuser.me/api/portraits/…
. Using external data sources with client-side applications might require CORS if resources are scripts or accessed through JavaScript. Let’s create a micro-proxy and adjust the miner view template to point towards our micro-proxy.
Spring 5’s functional WebClient
Spring Framework 5 comes with a functional WebClient
that integrates with Project Reactor’s HTTP client for reactive HTTP communication. WebClient
can be used together with Spring WebFlux to proxy requests to a different host and stream back results.
Steps
-
Go to
MinerController
and create two handler methods, one mapped toGET /miner/{id}/avatar
and the other mapped to/miner/{id}/avatar/small
ReturningMono<ResponseEntity<Flux<ByteBuffer>>>
is a good idea because HTTP response headers (Content-Type
) should be set. -
Create a
WebClient
instance initialized at instance-level withWebClient.builder().clientConnector(new ReactorClientHttpConnector()).build()
. -
Implement the mapped methods: Lookup
User
byid
from the URL mapping. Fetch theUserProfile
and request the avatar URL withWebClient
. -
Initiate web exchange and map the result. Construct
HttpHeaders
by extracting theContent-Type
header from the proxy target request so the current response passes the header value through. Return the response status and body asByteBuffer
(ClientResponse.bodyToFlux(ByteBuffer.class)
) inside aResponseEntity
. -
Go to
src/main/resources/templates/miner.ftl
. Replace the avatar image URL to point to/miner/${model.nickname}/avatar
and small avatar to/miner/${model.nickname}/avatar/small
. -
Start now the application again. Click on a miner once the page has loaded. Inspect the avatar image sources.
Your code could look like:
@Controller
@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true)
@RequiredArgsConstructor
public class MinerController {
UserRepository userRepository;
UserStatRepository userStatRepository;
WebClient webClient = WebClient.builder()
.clientConnector(new ReactorClientHttpConnector()).build()
.filter(userAgent());
@GetMapping("/miner/{id}")
String getMiner(@PathVariable String id, Model model) {
Mono<MinerModel> compositeModel = userRepository.findOne(id)
.and(user -> userStatRepository.findByUserId(user.getId()))
.map(tuple -> MinerModel.of(tuple.getT1(), tuple.getT2()));
model.addAttribute("model", compositeModel);
return "miner";
}
@GetMapping("/miner/{id}/avatar")
@ResponseBody
Mono<ResponseEntity<Flux<ByteBuffer>>> getAvatar(@PathVariable String id) {
return fetchAvatar(userRepository.findOne(id).map(User::getUserProfile)
.map(UserProfile::getAvatarUrl));
}
@GetMapping("/miner/{id}/avatar/small")
@ResponseBody
Mono<ResponseEntity<Flux<ByteBuffer>>> getSmallAvatar(@PathVariable String id) {
return fetchAvatar(userRepository.findOne(id).map(User::getUserProfile)
.map(UserProfile::getSmallAvatarUrl));
}
private Mono<ResponseEntity<Flux<ByteBuffer>>> fetchAvatar(Mono<String> map) {
return map.then(s -> webClient.get().uri(s).exchange()) //
.map(resp -> {
HttpHeaders headers = new HttpHeaders();
Optional<MediaType> asString = Optional.ofNullable(resp.headers()
.asHttpHeaders().getContentType());
headers.add(HttpHeaders.CONTENT_TYPE, asString
.map(MimeType::toString).orElse(MediaType.IMAGE_JPEG_VALUE));
return new ResponseEntity<>(resp.bodyToFlux(ByteBuffer.class),
headers, resp.statusCode());
});
}
private ExchangeFilterFunction userAgent() {
return (clientRequest, exchangeFunction) -> {
ClientRequest newRequest = ClientRequest.from(clientRequest)
.header("User-Agent", "Spring Framework WebClient").build();
return exchangeFunction.exchange(newRequest);
};
}
}
Congratulations, you have finished this exercise.


I followed the procedure in previous FAQ and am still having problems with my wallet.
Read it completely before use.
General remarks on CLI wallet:
- On Windows command line enter the commands as shown without the surrounding quotation marks
- In Linux shell preceed the commands without surrounding quotation marks with ./
- In MacOS shell preceed the commands without surrounding quotation marks with ./
General remarks on Windows command line formatting:
- The CLI help shows the command format for Linux and MacOS.
- For windows substitute the shown '-character with the "-character.
- For windows substitute the shown "-character with the \"-characters.
'VRSC Wallet location` and `VRSC.conf location` on different OS: Linux GUI: `~/.Komodo/VRSC` Mac OS: `/Users//Library/Application Support/Komodo/VRSC` Windows 10: `%AppData%\Komodo\VRSC\`
Procedure:
To completely reset your wallet in the event of a fork, particularly if you've already followed the previous FAQ procedure, follow the steps below. 1. Open your VRSC.conf file for editing. 2. Add a line to VRSC.conf containing (mac or linux) exportdir=/home// (or on windows) exportdir=c:\Users\ \Desktop\ 3. Save the file and stop verusd. For Agama or Verus Desktop just exit and wait for it to close completely. For the cli run `verus stop`. 4. Once your wallet is finished closing make a backup of your wallet.dat file somewhere safe. wallet.dat is located in the same directory as your configuration file (see above). To make the backup just copy it to another directory, make sure to leave the original there for the time being. 5. Now restart your wallet by launching Agama, Verus Desktop or running `verusd` for the CLI. 6. Now we'll export the wallet (this produces a different kind of file from what we did above). (Agama) Go to settings, scroll to the bottom and click CLI, select VRSC in that section, then below `type z_exportwallet mywalletexport` and click the button below to run it. (Verus Desktop) Got to settings, click on Coin settings and in the native client terminal type `run z_exportwallet mywalletexport` (CLI) `verus z_exportwallet mywalletexport` The exported wallet should be a file called mywalletexport in the location you set for exportdir in VRSC.conf. Keep this file secure, it has your plaintext private keys. Verify that the file is there and isn't empty. 7. Stop Verus again by closing Agama, Verus Desktop or running `./verus stop` for the linux CLI or `verus stop` for the windows CLI. 8. Making ABSOLUTELY SURE you have both the mywalletexport file and your wallet.dat backup in a safe place, delete your komodo/VRSC directory and everything in it (you can optionally leave your VRSC.conf file, but everything else there should be deleted). 9. At this point make sure you're on the latest version for your wallet by going to https://veruscoin.io/wallet.html and checking the downloads section. If you need to upgrade do so now, before starting your wallet again. 10. Restart your wallet by launching Agama, Verus Desktop or running `verusd` for the CLI. Allow it to start syncing. 11. Once it has begun syncing, you can import your wallet. In either case, replace with the full path to your wallet export file - on windows this might look like c:\Users\John\Desktop\mywalletexport , on linux or mac it would look something like /home/john/mywalletexport . (Agama) Go to settings, scroll to the bottom and click CLI, select VRSC in that section, then below type `z_importwallet ` and click the button below to run it. (Verus Desktop) Got to settings, click on Coin settings and in the native client terminal type `run z_omportwallet ` (CLI) Run `verus z_importwallet ` Depending on the number of addresses in your wallet and how far along you are on re-syncing, this may take several minutes to complete. Your balances will adjust as the chain syncs, as it only knows about the transactions that have happened in the blocks it has received and scanned. That means your balance will adjust as new blocks are scanned and won't reflect an accurate balance until you are fully synced.


| App | App-Instance | Version | Host | Node IP | Last Deploy | Container Name/ID | Application Type | Status | Logs | Upgrade |
| App | App-Instance | Version | Host | Node IP | Last Deploy | Container Name/ID | Application Type | Status | Logs | Upgrade |
| S.No. | Application Name | Application Description |
| Application Details | Application Values |
|---|---|
| Application Name : | |
| App-Instance Name : | |
| Version : | |
| Host : | |
| Node IP : | |
| Last Deploy : | |
| Container Name/ID : | |
| Application Type : | |
| Status : |


Deuteronomy 4:35
Unto thee it was showed, that thou mightest know that the LORD he is God; there is none else beside him.


Example
1. Get start, load/write/process image (OS any)
2. Draw image (Windows)
3. Create bitmap region window (Windows)
4. Use ImageStone in DLL (Windows)
5. Use FreeImage library to read/write image (OS any)
6. Custom image format (OS any)
7. Custom pixel processor (OS any)
8. MFC Demo (Windows)
9. Draw text on image (Windows)
10. Load jpeg's EXIF information (Windows)


CA Certificate File Info
The CA (Certificate Authority) certificate file is needed so that PHPCap can verify that the REDCap instance it is connecting to is actually the instance that was specified.
In PHPCap, it is possible to set SSL verification to false, so that a CA certificate file is not required, however, this is insecure, and is not recommended. At most, setting SSL verification to false should only be used for initial testing with non-critical data.
It is possible that your system may already be set up to use a correct CA certificate file. This can be tested by trying to access a project with SSL verification set to true, but with no CA certificate file specified, for example:
<?php
require('PHPCap/autoloader.php');
use IU\PHPCap\RedCapProject;
$apiUrl = 'https://redcap.someplace.edu/api/'; # Replace with your REDCap's API URL
$apiToken = '1234567890A1234567890B1234567890'; # Replace with your API token
$sslVerify = true;
$project = RedCapProject($apiUrl, $apiToken, $sslVerify);
$project->exportProjectInfo();
If this works, then that would indicate that your system is already set up with a CA certificate file. If it fails, and you get an error message about a security certificate, such as
SSL certificate problem: self signed certificate in certificate chain
then your system is not already set up.
Creating a CA Certificate File with Firefox
To use the Firefox web browser to create a CA (Certificate Authority) certificate file for use with PHPCap, use the following steps:
- Access your REDCap site with Firefox.
-
Click on the padlock icon to the left of the URL displayed in Firefox, and then the connection, and then "More Information".
-
If the previous step succeeded, a "Page Info" window should open up. In this window, click on the "Security" tab, if it is not already selected.
- Click on the "View Certificate" button
-
Click on the "Detail" tab of the "Certificate Viewer" dialog.
- Select the top entry in the "Certificate Hierarchy" box.
- Click the "Export..." button.
-
In the "Save Certificate to File" window that should appear:
- navigate to where you want to save the file
- change the name of the file if you don't want to use the default name
- set "Save as type" to "X.509 Certificate (PEM)"
-
click on the "Save" button.


My name is Jessica Bertling, and I'm a Web Designer and Front End Developer living on the East Central Florida coast. I specialize in e-commerce design and usability, and am currently a UI/UX Designer employed by MAG Retail & Media.
View PortfolioAs the device market continues to boom, having a responsive design is more important than ever. I'm well versed in the art of responsive design, from mockups to completed projects, and enjoy the challenge of solving design issues for every width.
When creating a successful website, user data is key. From in-person usability testing to software-based mass testing, I enjoy collecting data and applying it to my design and interaction decisions to increase both sales and user satisfaction.
 I enjoy working with responsive layouts, web typography, and the latest techniques. I enjoy writing fun jquery interactions without relying on plugins.
Having a well thought out & designed website is nice, but it also needs to be found. One of the key areas of SEO, the markup, is often placed in the front end developers hands. I know the proper way, and a few tricks, to get the most benefit when being crawled.
Mag Retail & Media
UI/UX Designer
November 2012 - Present
Work on design and front end development for all domains held by J&P Cycles, Motorcycle Superstore, Cycle News, & Motorcycle USA.
J&P Cycles
Web Designer II
November 2007 - November 2012
Grew from banner / email design to doing all of the design and front end development work for all of JPCycles.com and it's subdomains.
When I'm not working in my office, you can normally find me enjoying dinner at a local restaurant or enjoying all the natural wonders that Florida has to offer. A beach lover at heart, my favorites include surfing, body boarding, snorkeling, and beachcombing for treasures.


Contents
-
Clarify all previous points
-
Calculate profit for one Thai snack
-
Find and calculate Thai Drinks
-
Start designing Picture Coding (Progress on Sunday)
-
Design activities for home coming:
-
Games of teamwork
-
Use space in basketball court
-
3 or 4 games:
-
Investigate on Line Coupons
-
Keep working on Website -> Finish on next Sunday
-
Proposal for 9 activities
-
First day of School Videos


Below some tools you can use for scans and vulnerability assessment while performing a penetration test:
exploit-db: The Exploit Database
grabber: web application scanner
inguma: pentest toolkik which can perfom target auditing and information gathering
Metasploit: “world’s most used penetration testing software”
Nessus: vulnerability scanner
Nikto: an Open Source web server scanner
oscanner: oracle assessment framework
searchsploit: search in exloit-db database
to be continued…


Today, I am briefly going to describe how I will be designing my index.html webpage. My index.html webpage will be the first thing that prospective employers and prospective clients will see when they they visit my page in the future. This page will act as a showcase for my talents and will be an extension of my personality.
My overall goal of this project is to create a landing page that will give prospective clients and employers an idea of what type of work I do. I would like the page to be an extension of my image. I will try to keep the page elegant, classy and modern. Top left, I plan to design a logo infused into my name. Top right, I will have links to my work, a page that tells about me and a link to this wonderful blog that you are enjoying now. Below that, I will have a large image of myself that is with a captivating backdrop. Below the image, I will have links to my social media and general accomplishments listed. Feedback is welcome, as always.


Question 01
Reponse 01
Question 02
Reponse 02
Question 03
Reponse 03
Question 04
Reponse 04
Question 05
Reponse 05


materia¶
Materia is a Javascript library for creating browser-based 3D visualizations of atomistic structures and other material properties. Check the demos and installation guide for further details.
Changelog¶
- 0.0.10:
Fixed issue in the detection of the visualization boundary for the BrillouinZoneViewer.
- 0.0.7:
Fixed issue with automatic fitting to canvas.
- 0.0.6:
Added BrillouinZoneViewer.
Added Toon material for StructureViewer.
Fixed issues with shadows.


Twitter rolling out fix for buggy auto-refresh timeline behavior on iOS
by Chance MillerOver the weekend, Twitter for iPhone users started experiencing buggy auto-refresh behavior following an app update. Essentially, the timeline would refresh randomly, causing people to lose track of what they were reading. Now, Twitter says that it is rolling out a fix for the problem.
As we speculated yesterday, the Twitter auto-refresh functionality was likely meant to happen seamlessly, with new tweets being silently inserted at the top. Instead, the actual functionality was anything but seamless.
 For instance, you would be in the middle of reading a tweet, and your timeline would refresh and jump to the top, causing you to lose your spot in your timeline.
In a post today, Twitter says that a fix for this problem is rolling out now with version 8.1.5 of its iOS app:
A fix for the auto-scrolling bug is rolling out now! Thanks for your patience while we worked on this. Please update your iOS app to version 8.1.5 when it becomes available for you.
Twitter for iOS is available as a free download on the App Store. Be sure to update today in order to prevent the auto-refresh timeline bug from affecting you any longer.
Last month, Twitter CEO Jack Dorsey teased that the company may be planning to re-open aspects of its API to third-party developers. This would help apps like Tweetbot and Twitterrific compete with the first-party Twitter app, but specific details are unknown at this point.
Read more:
- iPhone Twitter users frustrated by buggy auto-refresh behavior in latest app update
- Twitter returns to the Mac with new Catalyst app now available for download
- Twitter for Mac receives first update since iPad version adapted for macOS
- Twitter may be planning to fix third-party clients after breaking Tweetbot and Twitterrific
FTC: We use income earning auto affiliate links. More.


{% extends "global/Base.html" %} {% load staticfiles otree %} {% comment %} {% endcomment %} {% block scripts %} {% endblock %} {% block title %}
Before you start making the {{ Constants.num_rounds }} decisions about how to spend your endowment (you will have ${{ Constants.endowment }} for each decision)


Globally tracking COVID-19, using data from Johns Hopkins University.
Confirmed cases (New cases)
Deaths (New deaths)


Provide backup functionality for your application and the ability to restore it to a known safe state.
This functionality is important because it allows the system to function in a safe and secure mode in case it is compromised or unavailable due to various failures or misconfiguration. Unsecure operation may lead to compromise of sensitive data or loss of system integrity.
Use this measure if the system allows a change of its configuration or its state of operation. Including this functionality is especially important if a change of parameters can introduce security risks, degrade performance, or affect system availability.
To implement recovery to a known safe state:
Identify all possible system states or modes of operation. Review your system requirements. Identify which states or modes of operation are available for the system and which state-to-state transitions are permissible.
Identify system configuration parameters. For every state, define all possible configuration parameters. Consult platform documentation to find out which mechanisms are available to store system parameters.
Use role-based authorization. Do not allow unauthorized users to change system states or modify parameters. Reserve this option only for users with system-defined roles like ‘admin’ or ‘security officer’. Check the target platform documentation to see which authentication mechanisms are available..
Implement backup functionality. Before any system modification, perform a backup of the system configuration in a safe location, such as network or external storage. If possible, prevent access to the backup by unauthorized users. If available, use cryptographic services to ensure backup integrity.
Implement restore functionality. Design a special restore feature to be able to recover the system from a previous backup. Enable backup integrity verification before performing the restore procedure. Don’t forget to authorize the user who performs system restoration.
Provide restore functionality as a separate utility. In case the application gets into an unavailable state and, therefore, cannot be operated, it is very important to have an external utility that can be operated independently from the application. For embedded systems, which may lack access to devices like a keyboard or display, a hot-key combination may be used to trigger a restore operation.
Log every system modification activity. For audit purposes, use a logging mechanism to record all the activity pertaining to changing system configuration parameters. Consult platform documentation to see which logging options are available. If available, use cryptographic services to ensure log integrity.


Bayern keeper Fruchtl signs new contract
by BeSoccerChristian Fruchtl has committed his future to Bayern Munich, agreeing a contract extension through to the end of the 2021-22 season.
Bayern Munich have tied 19-year-old goalkeeper Christian Fruchtl to a new contract that keeps him in Bavaria until 2022.
The Germany Under-20 international's deal with the Bundesliga champions had been set to expire at the end of the season.
Fruchtl, who joined the club in 2014, is yet to feature for the Bayern first team but has been named on the bench 12 times since the start of 2017-18.
"It’s a great feeling that the best club in Germany has put its faith in me," he said. "I want to continue making a name for myself this season in the third division [with the reserve team] and push for the first team.
Featured links
- BREAKING NEWS: Mourinho replaces Pochettino at Tottenham
- The latest football transfers news and rumours
- Wales, golf, Madrid... in that order
- Luis Enrique returns to Spain national team
"When you train with world-class players on a daily basis, you also mature as a person. That's always been something special for me."
Sporting director Hasan Salihamidzic added: "Christian is a true Bavarian boy and has grown up here in the club. We're very pleased to have him.
"He's shown continuous development and we want to continue that together. We're certain he's got a great career in front of him."


If you are looking to hire and drive that memorable and nostalgic car for your special wedding day then we have cars to suit all tastes and budgets within our collection of 80s and 90s classics.

We have cars from Maserati, Mercedes, BMW, Porsche and Aston Martin to name a few, so we are sure you will find something ideal to fit your perfect wedding day.


WITNESS LIST Appropriations-S/C on General Government Committee (Subcommittee on Budget Oversight Charge #2) June 18, 2002-9:30A Interim Charge #2 For: Harris, Judge Ron (Tx Clean Air Working Group) Meraz, Gloria (Texas Library Association) On: Buckley, Robert (Soil and Water Conservation Board) Carlson Reed, Cassie (TWC) Carrington, Edwina (TDHCA) Demerson, Aaron (Tx Dept. of Economic Development) Glacken, Shawn (Assoc. of Electric Companies of Tx) Huston, Robert (TNRCC) Kimbrough, Jay (Governor's Office) Martin, Dan (Tx Dept. of Economic Development) Mathews, Jim (N.E. Tx Air Care) Moore, James (Tx Soil and Water Conservation Board) Morphew, Cindy (Tx OIl and Gas Assoc.) Morrissey, Mike (Governor's Office) Moseley, Jeff (Tx Dept of Economic Development) Rath, Diane (TWC) Rudd, Peggy (Tx State Library) Saitas, Jeff (TNRCC) Settlemeyer, Herman (Texas River Compact Commissions) Smith, Tom (Self) Taylor, Dub (Comptroller/State Energy Conservation Office) Townsend, Randy (TWC) Tucker, Jerry (Governor's Office)


--- layout: post title: The Open Data Protocol (OData) Workshop By Woodruff Solutions date: 2014-11-25 13:51:30.000000000 +08:00 categories: - OData ecosystem - OData events - OData services - OData tutorials tags: [] status: publish type: post published: true author: Chris Woodruff ---
Does your organization build web and mobile applications for your customers, clients and/or employees? Do you want to get those applications out into their hands quicker and with less maintainability from your already over-worked IT staff? Knowing and understanding what the Open Data Protocol (OData) can bring to your enterprise will allow you to build one data platform for all aspects of your IT needs. It will open up a new way to look at your data that you may not have thought possible.
Interested in OData? Want to discover what the next revolution in data will be? In this workshop, the attendee is invited to consider the many opportunities and challenges for data-intensive applications, inter-organizational data sharing for “data mashups,” the establishment of new processes and pipelines, and an agenda to exploit the opportunities as well as stay ahead of the data deluge.
The Open Data Protocol (OData) is a Web protocol for querying and updating data which provides a way to unlock your data and free it from silos that exist in applications today. OData does this by applying and building upon Web technologies such as HTTP, Atom Publishing Protocol (AtomPub) and JSON to provide access to information from a variety of applications, services, and stores.
OData is consistent with the way the Web works – it makes a deep commitment to URIs for resource identification and commits to an HTTP-based, uniform interface for interacting with those resources (just like the Web). This commitment to core Web principles allows OData to enable a new level of data integration and interoperability across a broad range of clients, servers, services, and tools.
The protocol emerged from experiences implementing AtomPub clients and servers in a variety of products over the past several years. OData is being used to expose and access information from a variety of sources including, but not limited to, relational databases, file systems, content management systems and traditional Web sites.
In this workshop Chris Woodruff of Woodruff Solutions LLC will go further and give hands on learning that will prepare the attendee when they leave the 2 day OData event.
Upon successful completion of this course, participants will be able to:
Woodruff Solutions LLC can customize the OData and ASP.NET Web API training to achieve specific organizational objectives.
Chris Woodruff (or Woody as he is commonly known as) has a degree in Computer Science from Michigan State University’s College of Engineering. Woody has been developing and architecting software solutions for almost 15 years and has worked in many different platforms and tools. He is a community leader, helping such events as GRDevNight, GRDevDay, West Michigan Day of .NET and CodeMash. He was also instrumental in bringing the popular Give Camp event to Western Michigan where technology professionals lend their time and development expertise to assist local non-profits. As a speaker and podcaster, Woody has spoken and discussed a variety of topics, including database design and open source. He has been a Microsoft MVP in Visual C#, Data Platform and SQL and was recognized in 2010 as one of the top 20 MVPs world-wide. Woody owns and leads Woodruff Solutions LLC to provide solutions involving mobile apps and the services that drive mobile solutions.
Participants should have high-level language programming experience and a working knowledge of Microsoft Visual Studio, C# and ASP.NET Web API.
Hands-on lecture/workshop
For more information or to discuss setting up a workshop for your organization contact Chris Woodruff at<EMAIL_ADDRESS>or call him at<PHONE_NUMBER>
| 8:45 am to 9:00 am | Introductions and Overview of the OData Workshop |
| 9:00 am to 10:00 am | Introducing the Open Data Protocol |
| 10:00 am to 10:30 am | The Metadata and Service Model of OData |
| 10:30 am to 10:45 am | Coffee Break |
| 10:45 am to 12:00 pm | URI Conventions of OData |
| 12:00 pm to 1:15 pm | Lunch |
| 1:15 pm to 2:00 pm | Hands-on Lab |
| 2:00 pm to 2:45 pm | Format Conventions of OData |
| 2:45 pm to 3:00 pm | Coffee Break |
| 3:00 pm to 3:45 pm | OData HTTP Conventions and Operations |
| 3:45 pm to 4:15 pm | Hands-on Lab |
| 4:15 pm to 4:30 pm | Recap and Review |
| 8:45 am to 9:00 am | Review of Day 1 and Overview of Day 2 |
| 9:00 am to 10:00 am | Going Beyond CRUD with OData |
| 10:00 am to 10:30 am | Extending OData |
| 10:30 am to 10:45 am | Coffee Break |
| 10:45 am to 12:00 pm | Hands-on Lab: Creating an OData Feed using ASP.NET Web API |
| 12:00 pm to 1:15 pm | Lunch |
| 1:15 pm to 2:00 pm | Overview: Consuming OData in a Windows 8/Windows Phone app |
| 2:00 pm to 2:45 pm | Hands on Lab: Consuming OData in a Windows 8/Windows Phone app |
| 2:45 pm to 3:00 pm | Coffee Break |
| 3:00 pm to 3:30 pm | Overview: Consuming OData in a Web App Using JSON |
| 3:30 pm to 4:15 pm | Hands-on Lab: Consuming OData in a Web App Using JSON |
| 4:15 pm to 4:30 pm | Recap and Review |


Killer whales circle and chase great white sharks in incredible footage
The clip was filmed in South Africa’s Seal Island off the coast of Mossel Bay and one person can be heard saying “that shark is scared”
by Sofie JacksonFootage has captured the moment great white sharks try and desperately swim away from killer whales.
The clip, filmed by Elton Polly in South Africa, shows the huge animals make a beeline for the sharks.
“That shark is scared,” someone can be heard saying in the background.
Dorsal fins can also be seen breaking the surface as the chase gets underway, reports the Daily Star.
One of the sharks, a smaller dark shape under the surface of the water, is just seconds ahead of a giant killer whale which can be seen clearly when it breaks through the waves.
A second killer whale circles around the outside and prevents the sharks from changing course.
In the video, it almost appears as if the orcas are using teamwork to herd the sharks — but it not clear if it is merely a fun game or dinner for the predators.
South Africa’s Seal Island off the coast of Mossel Bay – where the video was taken – is a favourite hunting ground of the great white shark.
Oceans Research shared the footage on Facebook and confirmed that killer whales were chasing the sharks in the video caption.
The group wrote: “Orcas were spotted chasing a white shark, and a few other white sharks were in the vicinity at the time.
“One white shark appears to be unnerved by the presence of the orcas, but another shark didn't seem too perturbed.
“We'll monitor the orca and white shark activity over the next few days, to see if there are any behavioural changes.”
Conservationist Richard Peirce previously told Daily Star Online that great white sharks are being hunted and killed by killer whales, also known as orcas, who feast on their livers.
The first documented sighting of killer whales eating great white sharks was back in 1997 off the Farallon Islands, near San Francisco.

Two killer whales, nicknamed Port and Starboard, have since been observed to rip out shark livers with surgical precision.


| special-ac: | {{ currentLteRanCellRestriction["lte-ran-cell-restriction"]["x-0005b9-mo-sig-barring-for-special-ac"] }} |
| x-0005b9-mo-sig-barring-factor: | {{ currentLteRanCellRestriction["lte-ran-cell-restriction"]["x-0005b9-mo-sig-barring-factor"] }} |
| x-0005b9-mo-sig-barring-time: | {{ currentLteRanCellRestriction["lte-ran-cell-restriction"]["x-0005b9-mo-sig-barring-time"] }} |


Name: {{cat.name}}
Breed: {{cat.breed}}
Description: {{cat.description}}
Birth Date: {{cat.birthday | date}}
Age in Cat Years: {{cat.birthday | catYears}}


Learn Japanese Kana
Cryptomeria
スギ
-
View kana chart
Beginner
-
Find some words
Scholar
-
Test yourself
Inspector
-
Test with all kana (hiragana and katakana, all lines)
Traveler
-
Get 50 / 50 in test (with all kana)
Fifty
-
Get 200 / 200 in test (with all kana)
Kana Star
-
Give me some feedback
Debugger
-
Donate me :)
Supporter


Finesse
Home
Warm up
Featured
Filter
Contact Us
Leg stretches
Arm stretches
Abs stretches
Butt stretches


Planning App
Calendar
Weather
ToDoList
Add Expenses
Welcome
Icon only
Calendar
Icon only
Weather
Icon only
ToDoList
What is the plan today :)
Save All
•
Clear All
Icon only
Add Expenses
Expenses:
Press
to add
Clear
Total:


End-to-end mTLS
If you want to use MTLS on otoroshi, you first need to enable it. It is not enabled by default as it will make TLS handshake way heavier. To enable it just change the following config :
otoroshi.ssl.fromOutside.clientAuth=None|Want|Need
or using env. variables
SSL_OUTSIDE_CLIENT_AUTH=None|Want|Need
You can use the Want
setup if you cant to have both mtls on some services and no mtls on other services.
You can also change the trusted CA list sent in the handshake certificate request from the Danger Zone
in Tls Settings
.
Otoroshi support mutual TLS out of the box. mTLS from client to Otoroshi and from Otoroshi to targets are supported. In this article we will see how to configure Otoroshi to use end-to-end mTLS. All code and files used in this articles can be found on the Otoroshi github
Create certificates
But first we need to generate some certificates to make the demo work
mkdir mtls-demo
cd mtls-demo
mkdir ca
mkdir server
mkdir client
# create a certificate authority key, use password as pass phrase
openssl genrsa -out ./ca/ca-backend.key 4096
# remove pass phrase
openssl rsa -in ./ca/ca-backend.key -out ./ca/ca-backend.key
# generate the certificate authority cert
openssl req -new -x509 -sha256 -days 730 -key ./ca/ca-backend.key -out ./ca/ca-backend.cer -subj "/CN=MTLSB"
# create a certificate authority key, use password as pass phrase
openssl genrsa -out ./ca/ca-frontend.key 2048
# remove pass phrase
openssl rsa -in ./ca/ca-frontend.key -out ./ca/ca-frontend.key
# generate the certificate authority cert
openssl req -new -x509 -sha256 -days 730 -key ./ca/ca-frontend.key -out ./ca/ca-frontend.cer -subj "/CN=MTLSF"
# now create the backend cert key, use password as pass phrase
openssl genrsa -out ./server/_.backend.oto.tools.key 2048
# remove pass phrase
openssl rsa -in ./server/_.backend.oto.tools.key -out ./server/_.backend.oto.tools.key
# generate the csr for the certificate
openssl req -new -key ./server/_.backend.oto.tools.key -sha256 -out ./server/_.backend.oto.tools.csr -subj "/CN=*.backend.oto.tools"
# generate the certificate
openssl x509 -req -days 365 -sha256 -in ./server/_.backend.oto.tools.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 1 -out ./server/_.backend.oto.tools.cer
# verify the certificate, should output './server/_.backend.oto.tools.cer: OK'
openssl verify -CAfile ./ca/ca-backend.cer ./server/_.backend.oto.tools.cer
# now create the frontend cert key, use password as pass phrase
openssl genrsa -out ./server/_.frontend.oto.tools.key 2048
# remove pass phrase
openssl rsa -in ./server/_.frontend.oto.tools.key -out ./server/_.frontend.oto.tools.key
# generate the csr for the certificate
openssl req -new -key ./server/_.frontend.oto.tools.key -sha256 -out ./server/_.frontend.oto.tools.csr -subj "/CN=*.frontend.oto.tools"
# generate the certificate
openssl x509 -req -days 365 -sha256 -in ./server/_.frontend.oto.tools.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 1 -out ./server/_.frontend.oto.tools.cer
# verify the certificate, should output './server/_.frontend.oto.tools.cer: OK'
openssl verify -CAfile ./ca/ca-frontend.cer ./server/_.frontend.oto.tools.cer
# now create the client cert key for backend, use password as pass phrase
openssl genrsa -out ./client/_.backend.oto.tools.key 2048
# remove pass phrase
openssl rsa -in ./client/_.backend.oto.tools.key -out ./client/_.backend.oto.tools.key
# generate the csr for the certificate
openssl req -new -key ./client/_.backend.oto.tools.key -out ./client/_.backend.oto.tools.csr -subj "/CN=*.backend.oto.tools"
# generate the certificate
openssl x509 -req -days 365 -sha256 -in ./client/_.backend.oto.tools.csr -CA ./ca/ca-backend.cer -CAkey ./ca/ca-backend.key -set_serial 2 -out ./client/_.backend.oto.tools.cer
# generate a pem version of the cert and key, use password as password
openssl x509 -in client/_.backend.oto.tools.cer -out client/_.backend.oto.tools.pem -outform PEM
# now create the client cert key for frontend, use password as pass phrase
openssl genrsa -out ./client/_.frontend.oto.tools.key 2048
# remove pass phrase
openssl rsa -in ./client/_.frontend.oto.tools.key -out ./client/_.frontend.oto.tools.key
# generate the csr for the certificate
openssl req -new -key ./client/_.frontend.oto.tools.key -out ./client/_.frontend.oto.tools.csr -subj "/CN=*.frontend.oto.tools"
# generate the certificate
openssl x509 -req -days 365 -sha256 -in ./client/_.frontend.oto.tools.csr -CA ./ca/ca-frontend.cer -CAkey ./ca/ca-frontend.key -set_serial 2 -out ./client/_.frontend.oto.tools.cer
# generate a pkcs12 version of the cert and key, use password as password
# openssl pkcs12 -export -clcerts -in client/_.frontend.oto.tools.cer -inkey client/_.frontend.oto.tools.key -out client/_.frontend.oto.tools.p12
openssl x509 -in client/_.frontend.oto.tools.cer -out client/_.frontend.oto.tools.pem -outform PEM
Once it’s done, you should have something like
$ tree
.
├── backend.js
├── ca
│ ├── ca-backend.cer
│ ├── ca-backend.key
│ ├── ca-frontend.cer
│ └── ca-frontend.key
├── client
│ ├── _.backend.oto.tools.cer
│ ├── _.backend.oto.tools.csr
│ ├── _.backend.oto.tools.key
│ ├── _.backend.oto.tools.pem
│ ├── _.frontend.oto.tools.cer
│ ├── _.frontend.oto.tools.csr
│ ├── _.frontend.oto.tools.key
│ └── _.frontend.oto.tools.pem
└── server
├── _.backend.oto.tools.cer
├── _.backend.oto.tools.csr
├── _.backend.oto.tools.key
├── _.frontend.oto.tools.cer
├── _.frontend.oto.tools.csr
└── _.frontend.oto.tools.key
3 directories, 18 files
The backend service
now, let’s create a backend service using nodejs. Create a file named backend.js
touch backend.js
and put the following content
const fs = require('fs');
const https = require('https');
const options = {
key: fs.readFileSync('./server/_.backend.oto.tools.key'),
cert: fs.readFileSync('./server/_.backend.oto.tools.cer'),
ca: fs.readFileSync('./ca/ca-backend.cer'),
};
const server = https.createServer(options, (req, res) => {
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({ message: 'Hello World!' }) + "\n");
}).listen(8444);
console.log('Server listening:', `http://localhost:${server.address().port}`);
to run the server, just do
node ./backend.js
now you can try your server with
curl --cacert ./ca/ca-backend.cer 'https://api.backend.oto.tools:8444/'
This should output :
{ "message": "Hello World!" }
now modify your backend server to ensure that the client provides a client certificate like:
const fs = require('fs');
const https = require('https');
const options = {
key: fs.readFileSync('./server/_.backend.oto.tools.key'),
cert: fs.readFileSync('./server/_.backend.oto.tools.cer'),
ca: fs.readFileSync('./ca/ca-backend.cer'),
requestCert: true,
rejectUnauthorized: true
};
const server = https.createServer(options, (req, res) => {
console.log('Client certificate CN: ', req.socket.getPeerCertificate().subject.CN);
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end(JSON.stringify({ message: 'Hello World!' }) + "\n");
}).listen(8444);
console.log('Server listening:', `http://localhost:${server.address().port}`);
you can test your new server with
curl \
--cacert ./ca/ca-backend.cer \
--cert ./client/_.backend.oto.tools.pem \
--key ./client/_.backend.oto.tools.key 'https://api.backend.oto.tools:8444/'
the output should be :
{ "message": "Hello World!" }
Otoroshi setup
Download the latest version of the Otoroshi jar and run it like
java \
-Dotoroshi.adminPassword=password \
-Dotoroshi.ssl.fromOutside.clientAuth=Want \
-jar -Dotoroshi.storage=file otoroshi.jar
[info] otoroshi-env - Admin API exposed on http://otoroshi-api.oto.tools:8080
[info] otoroshi-env - Admin UI exposed on http://otoroshi.oto.tools:8080
[info] otoroshi-in-memory-datastores - Now using InMemory DataStores
[info] otoroshi-env - The main datastore seems to be empty, registering some basic services
[info] otoroshi-env - You can log into the Otoroshi admin console with the following credentials<EMAIL_ADDRESS>/ password
[info] play.api.Play - Application started (Prod)
[info] p.c.s.AkkaHttpServer - Listening for HTTP on /0:0:0:0:0:0:0:0:8080
[info] p.c.s.AkkaHttpServer - Listening for HTTPS on /0:0:0:0:0:0:0:0:8443
[info] otoroshi-env - Generating a self signed SSL certificate for https://*.oto.tools ...
and log into otoroshi with the tuple<EMAIL_ADDRESS>/ password
displayed in the logs.
Once logged in, navigate to the routes page and create a new route.
- Set a name then validate the creation
- On frontend node, add
api.frontend.oto.tools
in the list of domains - On backend node, replace the target with
api.backend.oto.tools
as hostname and8444
as port.
Save the route and try to call it.
curl 'http://api.frontend.oto.tools:8080/'
This should output :
{"Otoroshi-Error": "Something went wrong, you should try later. Thanks for your understanding."}
you should get an error due to the fact that Otoroshi doesn’t know about the server certificate and the client certificate expected by the server.
We must declare the client and server certificates for https://api.backend.oto.tools
to Otoroshi.
Go to the certificates page and create a new item. Drag and drop the content of the ./client/_.backend.oto.tools.cer
and ./client/_.backend.oto.tools.key
files, respectively in Certificate full chain
and Certificate private key
.
If you prefer to use the API, you can create an Otoroshi certificate automatically from a PEM bundle.
cat ./server/_.backend.oto.tools.cer ./ca/ca-backend.cer ./server/_.backend.oto.tools.key | curl \
-H 'Content-Type: text/plain' -X POST \
--data-binary @- \
-u admin-api-apikey-id:admin-api-apikey-secret \
http://otoroshi-api.oto.tools:8080/api/certificates/_bundle
now we have to expose https://api.frontend.oto.tools:8443
using otoroshi.
Create a second item. Copy and paste the content of ./server/_.frontend.oto.tools.cer
and ./server/_.frontend.oto.tools.key
respectively in Certificate full chain
and Certificate private key
.
 On the target of the backend node, we have to enable the custom Otoroshi TLS.
- Click on the backend node
- Click on your target
- Click on the Show advanced settings button
- Click on Custom TLS setup
- Enable the section
- In the list of certificates, select the backend certificate
- In the list of trusted certificates, select the frontend certificate
- Save your route
Try the following command
curl --cacert ./ca/ca-frontend.cer 'https://api.frontend.oto.tools:8443/'
the output should be
{"message":"Hello World!"}
Now we want to enforce the fact that we want client certificate for api.frontend.oto.tools
.
Search in the list of plugins and add the Client Certificate Only
plugin to your route.
now if you retry
curl --cacert ./ca/ca-frontend.cer 'https://api.frontend.oto.tools:8443/'
the output should be
{"Otoroshi-Error":"bad request"}
you should get an error because no client certificate is passed with the request. But if you pass the ./client/_.frontend.oto.tools.csr
client cert and the key in your curl call
curl 'https://api.frontend.oto.tools:8443' \
--cacert ./ca/ca-frontend.cer \
--cert ./client/_.frontend.oto.tools.pem \
--key ./client/_.frontend.oto.tools.key
the output should be
{"message":"Hello World!"}
Client certificate matching plugin
Otoroshi can restrict and check all incoming client certificates on a route.
Search in the list of plugins the Client certificate matching
plugin and add it the the flow.
Save the route and retry your call again.
curl 'https://api.frontend.oto.tools:8443' \
--cacert ./ca/ca-frontend.cer \
--cert ./client/_.frontend.oto.tools.pem \
--key ./client/_.frontend.oto.tools.key
the output should be
{"Otoroshi-Error":"bad request"}
Our client certificate is not matched by Otoroshi. We have to add the subject DN in the configuration of the Client certificate matching
plugin to authorize it.
{
"HasClientCertMatchingValidator": {
"serialNumbers": [],
"subjectDNs": [
"CN=*.frontend.oto.tools"
],
"issuerDNs": [],
"regexSubjectDNs": [],
"regexIssuerDNs": []
}
}
Save the service and retry your call again.
curl 'https://api.frontend.oto.tools:8443' \
--cacert ./ca/ca-frontend.cer \
--cert ./client/_.frontend.oto.tools.pem \
--key ./client/_.frontend.oto.tools.key
the output should be
{"message":"Hello World!"}


Digital Marketing Firm
Role: Founder & Growth Engineer
Stack: JavaScript, HTML, CSS
LaunchMachine provides digital marketing and growthhack solutions to help startups rapidly acquire customers.
As the founder and lead growth engineer, I was responsible for building our website and product offering. I was also resposible for helping clients achieve:
- ROI driven digital advertising (Facebook Ads with CPAs as low as $7).
- Custom websites and landing pages that increase social engagement (on average 120%)
- A/B split testing and U/X engagement optimization.
- Targeted media lists to get coverage (client PR wins include: BuzzFeed, NPR, FOX News, Business Times & Fortune).


Paying canceled
Paying were canceled. You may go back to cart to edit your order
{% extends "webshop/base_template.html" %} {% block title %}Nintendo Game & Watch Shop - Password Reset - Password Reset Complete{% endblock %} {% block extra-scripts %}{% endblock %} {% block page-title %}Password Reset{% endblock %} {% block sort-bar %}{% endblock %} {% block content %}
Paying were canceled. You may go back to cart to edit your order


From Excel to package.xml
Cleaning up an org that has gone through several generations of ownership and objectives is fun. Some tooling helps
Data frugality
A computing principle, very much the anathema to Google and Facebook, is Data Frugality, storing only what you actually need. It is the data equivalent to coders' YAGNI principle. Latest since GDPR it got center stage attention.
Your cleanup plan
So your cleanup exercise has a few steps:
- Find fields that don't have any data. You can use tools like Field Trip to achieve that
- Verify that these fields are not "about to be used", but "really obsolete"
- Add all the fields that did have some data left over, but unused now
- Add fields that contain data legal told you to get rid off
The absolute standard approach, of any consultant I have encountered, is to fire up an Excel sheet and track all fields in a list, capture insights in the remarks
column and have another column that indicates can be deleted
Status. Something like Yes,No,Investigating
or "Call Paul to clarify". I would be surprised if there's a different approach in the wild (in theory there are).
Excel as source?
In a current project the consultant neatly created one sheet (that's the page, not the file) per object, labeled with the object name, containing rows for all custom fields. Then the team went off to investigate. In result they identified more than one thousand fields to be deleted.
Now to actually get rid of the fields, you could outsource some manual labor to either go into you org or use Copy-Paste to create a destructivechanges.xml
package file for use with the Salesforce ANT tool.
In any case: the probability that there will be errors in transferring is approximately 100%. The business owner will point to: I signed off that spreadsheet and not that XML file! Finger pointing commencing.
There must be a better way
XML and XSLT to the rescue
Since I encounter Excel based list quite frequently, I wrote a small tool that converts Excel to XML. It is specifically designed to cater to lists, and lists only. The result is XSLT friendly, with cells carrying proper row and column properties and computed cells carrying the last result and not the formula.
In case you wonder why, read my previous post or the OOXML specifications (The later might take you a while).
A quick command line generated the XML: java -Xmx4g -jar excel2xml.jar -i deadfieldsreport.xslx -o destructivechanges.xml -s
that had:
- Object name in sheet name
- Field name in column 0
- Status that determined deletability in column 5
less than 40 lines XSLT did the job.
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
xmlns="http://soap.sforce.com/2006/04/metadata" exclude-result-prefixes="xs xd" version="2.0">
<xsl:output encoding="UTF-8" indent="yes" method="xml"/>
<xsl:param name="fieldNameColumn" select="'0'"/>
<xsl:param name="statusColumn" select="'5'"/>
<xsl:param name="isDeletable" select="'yes'"/>
<xsl:template match="/">
<Package>
<xsl:apply-templates
select="workbook/sheet[row/cell[@col = $statusColumn and lower-case(text()) = $isDeletable]]"/>
<version>45.0</version>
</Package>
</xsl:template>
<xsl:template match="sheet">
<xsl:variable name="oName" select="@name"/>
<xsl:element name="types">
<!-- xsl:attribute name="object"><xsl:value-of select="$oName"/></xsl:attribute -->
<xsl:apply-templates
select="row/cell[@col = $statusColumn and lower-case(text()) = $isDeletable]">
<xsl:with-param name="oName" select="$oName"/>
</xsl:apply-templates>
<name>CustomField</name>
</xsl:element>
</xsl:template>
<xsl:template match="cell">
<xsl:param name="oName"/>
<members><xsl:value-of select="replace($oName, ' ', '')"/>.<xsl:value-of
select="../cell[@col = $fieldNameColumn]"/></members>
</xsl:template>
</xsl:stylesheet>
The nice side effect: it is repeatable. Just fetch the latest Excel file and run it through. Since no Excel installation is required, you can make this approach part of your CI pipeline.
As usual: YMMV
Posted by Stephan H Wissel on 23 February 2019 | Comments (0) | categories: Salesforce XML


Sito is like shadow If you already have Sito buyer account OR Use this form for new buyer: 4 - Count of sellers


Missing fields
Please check the following errors and try again.
-
{% if errorMissingSector %}
- Sector: missing {% endif %}
Which sector do you work in?
Why are we asking this?
{% include "includes/basket.html" %}
{% extends "layout.html" %} {% if loggedIn == undefined %} {% set loggedIn = false %} {% endif %} {% set external_journey = true %} {% block after_header %} {% endblock %} {% block page_title %} GOV.UK prototype kit {% endblock %} {% block content %} {% include "includes/great-header-beta-signed-in.html" %} {% macro createSectorList(name) %}
Please check the following errors and try again.


--- layout: post title: Ship mills published: true ---
Above: Boat mill, Encyclopédie Diderot, 1751
Above: boat mill, Fausto Veranzio, 1617
Above: boat mill, Fausto Veranzio, 1617
Above: miniature of a boat mill
Above: german ship mill, 1840
One of the last authentic boat mills in France, around 1914
Above: the last ship mill on the Rhône in Lyon, France, 1894
Above: ship mill on the Tisza, Hungary (from the postcard collection of Ton Meesters)
Above: reconstruction of a ship mill in repair (1990s). Photo: Karel Broes.


Stop allowing your mind to be a slave, to be jerked around by selfish impulses, to kick against fate and the present, and to mistrust the future.
 Even chance is not devolved from nature.
Concentrate every minute like a man on doing what is infront of you with precise and genuine seriousness.

Never act under compulsion, out of selfishness, or without forethought.
Look at how we’re all forgotten. The abyss of endless time that swallows it all.
Be straightforward, act without pretension.
You don’t love yourself enough. Or you’d love your nature too, and what it demands of you. People who love what they do wear themselves down doing it, they even forget to wash or eat.
Do you have less respect for your own nature than the engraver does for engraving?


|
Figure 1
|
A recently logged forest plot near the edge of the São Franc ... |
|
Figure 2
|
Annual mean minimum temperature (°C) (a) winter minimum temp ... |
|
Figure 3
|
Loess curve fitted to annual rainfall data for the 0.5 × 0.5 ... |
|
Figure 4
|
Autocorrelation functions of the residuals of linear regress ... |
|
Figure 5
|
Nonmetric multidimensional scaling (NMDS) ordination of subt ... |
|
Figure 6
|
Proportions of trees belonging to different ecological group ... |
|
Figure 7
|
Biomass rate of net change in mixed subtropical forest stand ... |
|
Figure 8
|
Tree turnover in mixed subtropical forest stands subjected t ... |
|
Figure 9
|
Community‐level weighted means of six functional traits in m ... |
|
Figure 10
|
Changes in community‐level weighted means of six functional ... |
|
Figure 11
|
(a) The functional dispersion index in mixed subtropical for ... |


Welcome
This is a Grapics Designer Web site. World Best Web Desing Site here make it. How to make your website! Easy for make & Earn your site.Gallery option click & see Make website sample.choose Sample & tell code Samples. Thank You.
Our Story
Photograper began in 2018. After years in the web industry. we realized that itwas near impossible for the average jane or joe to create their own website.Traditional web hosting services were simply too complicated,time consuming, and expensive to manage.


Overview
One very useful feature of the Character Editor is the Validator found in the main toolbar. This allows you validate either the current character, or all characters.
Validation looks over the character's files for any problems: missing images, invalid dialogue (bad conditions, variables, etc.) and more.
Before committing anything back to the repository, you should always validate your character. This ensures that your character is always at the minimum fully functional.
Validation Results
After validating one or all characters, you will be taken to the Results screen which will list all issues with the characters validated.
The bottom left has a list of filters. If you are interested in seeing only a certain subset of issues, check and uncheck the appropriate filters here.


|
sound_variable = variable previously assigned with a LoadSound command.
flags = optional playback flags |
|
This plays a sound previously loaded and assigned to a variable using the LoadSound command.
The returned value is a 'channel handle'. Various channel commands allow you to modifiy the sound while it is playing in realtime. The optional flags variable can be of the following values: 1: Loop the sound 2: Pause the sound 3: Loop and pause the sound If a paused flag is specified, you must use ResumeChannel to actually start the audio output. Pausing a sound before playback allows you to setup various channel parameters before the sound actually starts playing. |
|
; Assign a global variable for the sound
Global sndPlayerDie ; Load the sound file into memory sndPlayerDie=LoadSound("sounds/die.wav") ; Play the sound chnDie=PlaySound ( sndPlayerDie ) |


| Name | Status | |||
|---|---|---|---|---|
| {{ building.name }} | Active | Closed |
| Name | Status | Access | Hours | |||
|---|---|---|---|---|---|---|
| {{ lot.name }} | Active | Closed | {{ lot.accessNames }} | {{ lot.start }}-{{ lot.end }} |
| Name | Status | Access | Hours | Instructions | |||
|---|---|---|---|---|---|---|---|
| {{ gate.name }} | Active | Closed | {{ gate.accessNames }} | {{ gate.start }}-{{ gate.end }} | Click on the edit button to view instructions. |
| Name | Status | Hours | No. of Stops | |||
|---|---|---|---|---|---|---|
| {{ shuttle.name }} | Active | Closed | {{ shuttle.start }}-{{ shuttle.end }} | {{ shuttle.stopsCount }} |


Hello! I'm Ricky. I'm a full-stack software developer, and recent graduate of Nashville Software School as of September 2019. I have always been passionate about technology, solving problems, along with playing my part in a team to achieve a common goal. I am very eager to continue to grow as a developer to allow ideas to come to life, and where this career path will take me.
The perfect recipe tracker targeted toward users that often go "off the cuff" when it comes to making a recipe. The most common question when it comes to cooking is "how did you make this?" A user can create an account, and create recipes to track how they made "the perfect batch."
I created a pet adoption application that bridges the gap between user's and adoptable dogs located in the Greater Nashville area. Users can login, and can find dogs they are interested in. Users can then go to their own interested pet list and add notes to their favorite pets they have chosen.


Claire Huong Pham
I'm a 4th year undergraduate student at the University of California, San Diego studying Human-Computer Interaction. In my spare time I like going on road trips and taking photos! I don't really have anything substantial to share in terms of the work that I've done so far, but I hope that change that really soon. (i.e the end of Wi17!)
note: all of my anchors are going to redirect to test.html, because it bothers me that the anchor leads to nowhere. thank you!


| Date | Title | Details | created by | votes |
|---|---|---|---|---|
| {{ p.timestamp }} | {{ p.title }} | details | {{ p.createdby }} | {{ p.votes }} |
refresh proposals:
Delegate my voting power for all proposals:
Create a Proposal:
Title:
Details:
option 1:
option 2:
option 3:
option 4: