mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
auto merge of #2070 : larsbergstrom/servo/android_201404c, r=larsbergstrom,metajack
r? @metajack
This commit is contained in:
commit
55bac1900c
18 changed files with 134 additions and 41 deletions
22
Makefile.in
22
Makefile.in
|
@ -30,7 +30,7 @@ B := $(CFG_BUILD_DIR)
|
|||
MKFILE_DEPS := config.stamp $(call rwildcard,$(S)mk/,*)
|
||||
|
||||
CFG_GCCISH_CFLAGS += -DRUST_DEBUG
|
||||
CFG_RUSTC_FLAGS = -D unused-imports
|
||||
CFG_RUSTC_FLAGS += -D unused-imports
|
||||
|
||||
ifdef CFG_DISABLE_OPTIMIZE
|
||||
$(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE))
|
||||
|
@ -107,6 +107,12 @@ $(B)src/compiler/rust/rust-auto-clean-stamp: $(S)src/compiler/rust-auto-clean-tr
|
|||
|
||||
rust: $(CFG_RUSTC)
|
||||
|
||||
# These arguments are automatically provided by the Rust compiler's build process to
|
||||
# itself, so they must be specified later for our Rust modules.
|
||||
ifeq ($(CFG_OSTYPE),linux-androideabi)
|
||||
CFG_RUSTC_FLAGS += --target arm-linux-androideabi -C android-cross-path=$(CFG_ANDROID_CROSS_PATH)
|
||||
endif
|
||||
|
||||
# Strip off submodule paths to determine "raw" submodule names.
|
||||
SUBMODULES=$(shell echo $(CFG_SUBMODULES) | perl -p -e 's![A-Za-z0-9_-]+/!!g')
|
||||
|
||||
|
@ -131,6 +137,8 @@ endif
|
|||
# their name already, while others don't.
|
||||
DONE_$(1) = $$(B)src/$$(PATH_$(1))/lib*.dummy
|
||||
DEPS_SUBMODULES += $$(PATH_$(1))
|
||||
DEPS_SUBMODULES += $$(PATH_$(1))/.libs
|
||||
DEPS_SUBMODULES += $$(PATH_$(1))/src/.libs
|
||||
endef
|
||||
|
||||
# these will get populated.
|
||||
|
@ -157,7 +165,7 @@ endef
|
|||
define DEF_SUBMODULE_RULES
|
||||
|
||||
ENV_RLDFLAGS_$(1) = -L $$(CFG_BUILD_HOME)workspace/lib/$$(CFG_TARGET_TRIPLES)
|
||||
ENV_RLDFLAGS_$(1) += $$(foreach dep,$$(DEPS_$(1)),-L $$(B)src/$$(PATH_$$(dep)))
|
||||
ENV_RLDFLAGS_$(1) += $$(foreach dep,$$(DEPS_$(1)),-L $$(B)src/$$(PATH_$$(dep)) -L $$(B)src/$$(PATH_$$(dep))/.libs -L $$(B)src/$$(PATH_$$(dep))/src/.libs)
|
||||
|
||||
# variables that depend on dependency definitions from sub.mk!
|
||||
ENV_CFLAGS_$(1) = CFLAGS="$$(CFLAGS_$(1))"
|
||||
|
@ -336,7 +344,8 @@ servo: $(DEPS_servo)
|
|||
else
|
||||
servo: $(DEPS_servo)
|
||||
@$(call E, compile: $@)
|
||||
$(Q)$(RUSTC) $(RFLAGS_servo) -C gen-crate-map -o $@ $< --crate-type lib
|
||||
$(Q)$(RUSTC) $(RFLAGS_servo) -C gen-crate-map $< -o libservo.so --crate-type dylib
|
||||
touch servo
|
||||
endif
|
||||
|
||||
# Darwin app packaging
|
||||
|
@ -354,12 +363,11 @@ package: servo
|
|||
else ifeq ($(CFG_OSTYPE),linux-androideabi)
|
||||
package: servo
|
||||
mkdir -p sofile
|
||||
-exec cp -f {} $(CFG_BUILD_HOME)sofile \;
|
||||
find . ! \( \( -type d -path './sofile' -o -path './$(CFG_TARGET_TRIPLES)/src/compiler/rust' \) -prune \) -name '*.so' -type f | xargs cp -f -t $(CFG_BUILD_HOME)sofile
|
||||
find $(CFG_RUST_HOME)/lib/rustc/$(CFG_TARGET_TRIPLES)/lib/ -name '*.so' -type f -size +1c | xargs cp -f -t $(CFG_BUILD_HOME)sofile
|
||||
find . ! \( \( -type d -path './sofile' -o -path './$(CFG_TARGET_TRIPLES)/src/compiler/rust' \) -prune \) -name '*.so' -type f | xargs -I {} cp -f {} $(CFG_BUILD_HOME)sofile/
|
||||
find $(CFG_RUST_HOME)/lib/rustlib/$(CFG_TARGET_TRIPLES)/lib/ -name '*.so' -type f -size +1c | xargs -I {} cp -f {} $(CFG_BUILD_HOME)sofile/
|
||||
cd $(S)src/platform/android/servo-android-glue && make with-libs
|
||||
cd $(CFG_BUILD_HOME)
|
||||
cp $(S)src/platform/android/servo-android-glue/bin/ServoAndroid-debug.apk -t $(CFG_BUILD_HOME)
|
||||
cp $(S)src/platform/android/servo-android-glue/bin/ServoAndroid-debug.apk $(CFG_BUILD_HOME)
|
||||
|
||||
else
|
||||
|
||||
|
|
1
configure
vendored
1
configure
vendored
|
@ -385,7 +385,6 @@ case ${TARGET_OSTYPE} in
|
|||
probe CFG_RANLIB arm-linux-androideabi-ranlib
|
||||
|
||||
export PATH=${OLD_PATH}
|
||||
CFG_RUSTC_FLAGS="--target=${CFG_TARGET_TRIPLES} -C android-cross-path=${CFG_ANDROID_CROSS_PATH}"
|
||||
;;
|
||||
*)
|
||||
CFG_PATH=$PATH
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#[crate_id = "github.com/mozilla/servo#gfx:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
#[crate_type = "dylib"];
|
||||
#[crate_type = "rlib"];
|
||||
|
||||
#[feature(globs, managed_boxes, macro_rules, phase)];
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ impl FontHandleMethods for FontHandle {
|
|||
buf: ~[u8],
|
||||
style: &SpecifiedFontStyle)
|
||||
-> Result<FontHandle, ()> {
|
||||
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
|
||||
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
||||
if ft_ctx.is_null() { return Err(()); }
|
||||
|
||||
let face_result = create_face_from_buffer(ft_ctx, buf.as_ptr(), buf.len(), style.pt_size);
|
||||
|
@ -279,7 +279,7 @@ impl<'a> FontHandle {
|
|||
pub fn new_from_file(fctx: &FontContextHandle, file: &str,
|
||||
style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
|
||||
unsafe {
|
||||
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
|
||||
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
||||
if ft_ctx.is_null() { return Err(()); }
|
||||
|
||||
let mut face: FT_Face = ptr::null();
|
||||
|
@ -306,7 +306,7 @@ impl<'a> FontHandle {
|
|||
pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
|
||||
-> Result<FontHandle, ()> {
|
||||
unsafe {
|
||||
let ft_ctx: FT_Library = fctx.ctx.borrow().ctx;
|
||||
let ft_ctx: FT_Library = fctx.ctx.ctx;
|
||||
if ft_ctx.is_null() { return Err(()); }
|
||||
|
||||
let mut face: FT_Face = ptr::null();
|
||||
|
|
|
@ -25,7 +25,7 @@ use font_list::{FontEntry, FontFamily, FontFamilyMap};
|
|||
use platform::font::FontHandle;
|
||||
use platform::font_context::FontContextHandle;
|
||||
|
||||
use collections::hashmap::HashMap;
|
||||
use collections::HashMap;
|
||||
use std::libc;
|
||||
use std::libc::{c_int, c_char};
|
||||
use std::ptr;
|
||||
|
|
|
@ -9,6 +9,7 @@ use css::matching::{ApplicableDeclarationsCache, StyleSharingCandidateCache};
|
|||
use geom::size::Size2D;
|
||||
use gfx::display_list::OpaqueNode;
|
||||
use gfx::font_context::{FontContext, FontContextInfo};
|
||||
#[cfg(not(target_os="android"))]
|
||||
use green::task::GreenTask;
|
||||
use script::layout_interface::LayoutChan;
|
||||
use servo_msg::constellation_msg::ConstellationChan;
|
||||
|
@ -16,25 +17,44 @@ use servo_net::local_image_cache::LocalImageCache;
|
|||
use servo_util::geometry::Au;
|
||||
use servo_util::opts::Opts;
|
||||
use std::cast;
|
||||
#[cfg(not(target_os="android"))]
|
||||
use std::ptr;
|
||||
#[cfg(not(target_os="android"))]
|
||||
use std::rt::Runtime;
|
||||
#[cfg(not(target_os="android"))]
|
||||
use std::rt::local::Local;
|
||||
#[cfg(not(target_os="android"))]
|
||||
use std::rt::task::Task;
|
||||
use style::{ComputedValues, Stylist};
|
||||
use sync::{Arc, MutexArc};
|
||||
use url::Url;
|
||||
|
||||
#[cfg(target_os="android")]
|
||||
use std::local_data;
|
||||
|
||||
#[cfg(not(target_os="android"))]
|
||||
#[thread_local]
|
||||
static mut FONT_CONTEXT: *mut FontContext = 0 as *mut FontContext;
|
||||
|
||||
#[cfg(target_os="android")]
|
||||
local_data_key!(font_context: *mut FontContext)
|
||||
|
||||
#[cfg(not(target_os="android"))]
|
||||
#[thread_local]
|
||||
static mut APPLICABLE_DECLARATIONS_CACHE: *mut ApplicableDeclarationsCache =
|
||||
0 as *mut ApplicableDeclarationsCache;
|
||||
|
||||
#[cfg(target_os="android")]
|
||||
local_data_key!(applicable_declarations_cache: *mut ApplicableDeclarationsCache)
|
||||
|
||||
#[cfg(not(target_os="android"))]
|
||||
#[thread_local]
|
||||
static mut STYLE_SHARING_CANDIDATE_CACHE: *mut StyleSharingCandidateCache =
|
||||
0 as *mut StyleSharingCandidateCache;
|
||||
|
||||
#[cfg(target_os="android")]
|
||||
local_data_key!(style_sharing_candidate_cache: *mut StyleSharingCandidateCache)
|
||||
|
||||
/// Data shared by all layout workers.
|
||||
#[deriving(Clone)]
|
||||
pub struct LayoutContext {
|
||||
|
@ -71,6 +91,7 @@ pub struct LayoutContext {
|
|||
opts: Opts,
|
||||
}
|
||||
|
||||
#[cfg(not(target_os="android"))]
|
||||
impl LayoutContext {
|
||||
pub fn font_context<'a>(&'a mut self) -> &'a mut FontContext {
|
||||
// Sanity check.
|
||||
|
@ -139,3 +160,57 @@ impl LayoutContext {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// On Android, we don't have the __tls_* functions emitted by rustc, so we
|
||||
// need to use the slower local_data functions.
|
||||
// Making matters worse, the local_data functions are very particular about
|
||||
// enforcing the lifetimes associated with objects that they hold onto,
|
||||
// which causes us some trouble we work around as below.
|
||||
#[cfg(target_os="android")]
|
||||
impl LayoutContext {
|
||||
pub fn font_context<'a>(&'a mut self) -> &'a mut FontContext {
|
||||
unsafe {
|
||||
let opt = local_data::pop(font_context);
|
||||
let mut context;
|
||||
match opt {
|
||||
Some(c) => context = cast::transmute(c),
|
||||
None => {
|
||||
context = cast::transmute(~FontContext::new(self.font_context_info.clone()))
|
||||
}
|
||||
}
|
||||
local_data::set(font_context, context);
|
||||
cast::transmute(context)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn applicable_declarations_cache<'a>(&'a self) -> &'a mut ApplicableDeclarationsCache {
|
||||
unsafe {
|
||||
let opt = local_data::pop(applicable_declarations_cache);
|
||||
let mut cache;
|
||||
match opt {
|
||||
Some(c) => cache = cast::transmute(c),
|
||||
None => {
|
||||
cache = cast::transmute(~ApplicableDeclarationsCache::new());
|
||||
}
|
||||
}
|
||||
local_data::set(applicable_declarations_cache, cache);
|
||||
cast::transmute(cache)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn style_sharing_candidate_cache<'a>(&'a self) -> &'a mut StyleSharingCandidateCache {
|
||||
unsafe {
|
||||
let opt = local_data::pop(style_sharing_candidate_cache);
|
||||
let mut cache;
|
||||
match opt {
|
||||
Some(c) => cache = cast::transmute(c),
|
||||
None => {
|
||||
cache = cast::transmute(~StyleSharingCandidateCache::new());
|
||||
}
|
||||
}
|
||||
local_data::set(style_sharing_candidate_cache, cache);
|
||||
cast::transmute(cache)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ impl WindowMethods<Application> for Window {
|
|||
impl glut::ReshapeCallback for ReshapeCallbackState {
|
||||
fn call(&self, width: c_int, height: c_int) {
|
||||
let tmp = local_window();
|
||||
tmp.borrow().event_queue.with_mut(|queue| queue.push(ResizeWindowEvent(width as uint, height as uint)))
|
||||
tmp.event_queue.borrow_mut().push(ResizeWindowEvent(width as uint, height as uint))
|
||||
}
|
||||
}
|
||||
glut::reshape_func(glut_window, ~ReshapeCallbackState);
|
||||
|
@ -105,7 +105,7 @@ impl WindowMethods<Application> for Window {
|
|||
impl glut::KeyboardCallback for KeyboardCallbackState {
|
||||
fn call(&self, key: c_uchar, _x: c_int, _y: c_int) {
|
||||
let tmp = local_window();
|
||||
tmp.borrow().handle_key(key)
|
||||
tmp.handle_key(key)
|
||||
}
|
||||
}
|
||||
glut::keyboard_func(~KeyboardCallbackState);
|
||||
|
@ -114,16 +114,16 @@ impl WindowMethods<Application> for Window {
|
|||
fn call(&self, button: c_int, state: c_int, x: c_int, y: c_int) {
|
||||
if button < 3 {
|
||||
let tmp = local_window();
|
||||
tmp.borrow().handle_mouse(button, state, x, y);
|
||||
tmp.handle_mouse(button, state, x, y);
|
||||
} else {
|
||||
match button {
|
||||
3 => {
|
||||
let tmp = local_window();
|
||||
tmp.borrow().event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))));
|
||||
tmp.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)));
|
||||
},
|
||||
4 => {
|
||||
let tmp = local_window();
|
||||
tmp.borrow().event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))));
|
||||
tmp.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)));
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
@ -150,15 +150,13 @@ impl WindowMethods<Application> for Window {
|
|||
}
|
||||
|
||||
fn recv(&self) -> WindowEvent {
|
||||
if !self.event_queue.with_mut(|queue| queue.is_empty()) {
|
||||
return self.event_queue.with_mut(|queue| queue.shift().unwrap())
|
||||
if !self.event_queue.borrow_mut().is_empty() {
|
||||
return self.event_queue.borrow_mut().shift().unwrap();
|
||||
}
|
||||
|
||||
glut::check_loop();
|
||||
if !self.event_queue.with_mut(|queue| queue.is_empty()) {
|
||||
self.event_queue.with_mut(|queue| queue.shift().unwrap())
|
||||
} else {
|
||||
IdleWindowEvent
|
||||
}
|
||||
|
||||
self.event_queue.borrow_mut().shift().unwrap_or(IdleWindowEvent)
|
||||
}
|
||||
|
||||
/// Sets the ready state.
|
||||
|
@ -174,7 +172,7 @@ impl WindowMethods<Application> for Window {
|
|||
self.render_state.get() == RenderingRenderState &&
|
||||
render_state == IdleRenderState {
|
||||
// page loaded
|
||||
self.event_queue.with_mut(|queue| queue.push(FinishedWindowEvent));
|
||||
self.event_queue.borrow_mut().push(FinishedWindowEvent);
|
||||
}
|
||||
|
||||
self.render_state.set(render_state);
|
||||
|
@ -219,16 +217,16 @@ impl Window {
|
|||
let modifiers = glut::get_modifiers();
|
||||
match key {
|
||||
42 => self.load_url(),
|
||||
43 => self.event_queue.with_mut(|queue| queue.push(ZoomWindowEvent(1.1))),
|
||||
45 => self.event_queue.with_mut(|queue| queue.push(ZoomWindowEvent(0.909090909))),
|
||||
56 => self.event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32)))),
|
||||
50 => self.event_queue.with_mut(|queue| queue.push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32)))),
|
||||
43 => self.event_queue.borrow_mut().push(ZoomWindowEvent(1.1)),
|
||||
45 => self.event_queue.borrow_mut().push(ZoomWindowEvent(0.909090909)),
|
||||
56 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, 5.0 as f32), Point2D(0.0 as i32, 5.0 as i32))),
|
||||
50 => self.event_queue.borrow_mut().push(ScrollWindowEvent(Point2D(0.0, -5.0 as f32), Point2D(0.0 as i32, -5.0 as i32))),
|
||||
127 => {
|
||||
if (modifiers & ACTIVE_SHIFT) != 0 {
|
||||
self.event_queue.with_mut(|queue| queue.push(NavigationWindowEvent(Forward)));
|
||||
self.event_queue.borrow_mut().push(NavigationWindowEvent(Forward));
|
||||
}
|
||||
else {
|
||||
self.event_queue.with_mut(|queue| queue.push(NavigationWindowEvent(Back)));
|
||||
self.event_queue.borrow_mut().push(NavigationWindowEvent(Back));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
@ -253,14 +251,14 @@ impl Window {
|
|||
if pixel_dist < max_pixel_dist {
|
||||
let click_event = MouseWindowClickEvent(button as uint,
|
||||
Point2D(x as f32, y as f32));
|
||||
self.event_queue.with_mut(|queue| queue.push(MouseWindowEventClass(click_event)));
|
||||
self.event_queue.borrow_mut().push(MouseWindowEventClass(click_event));
|
||||
}
|
||||
}
|
||||
MouseWindowMouseUpEvent(button as uint, Point2D(x as f32, y as f32))
|
||||
}
|
||||
_ => fail!("I cannot recognize the type of mouse action that occured. :-(")
|
||||
};
|
||||
self.event_queue.with_mut(|queue| queue.push(MouseWindowEventClass(event)));
|
||||
self.event_queue.borrow_mut().push(MouseWindowEventClass(event));
|
||||
}
|
||||
|
||||
/// Helper function to pop up an alert box prompting the user to load a URL.
|
||||
|
@ -270,9 +268,9 @@ impl Window {
|
|||
alert.run();
|
||||
let value = alert.prompt_value();
|
||||
if "" == value { // To avoid crashing on Linux.
|
||||
self.event_queue.with_mut(|queue| queue.push(LoadUrlWindowEvent(~"http://purple.com/")))
|
||||
self.event_queue.borrow_mut().push(LoadUrlWindowEvent(~"http://purple.com/"))
|
||||
} else {
|
||||
self.event_queue.with_mut(|queue| queue.push(LoadUrlWindowEvent(value.clone())))
|
||||
self.event_queue.borrow_mut().push(LoadUrlWindowEvent(value.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,8 @@ use servo_util::opts;
|
|||
#[cfg(not(test))]
|
||||
use servo_util::url::parse_url;
|
||||
|
||||
#[cfg(not(test))]
|
||||
|
||||
#[cfg(not(test), not(target_os="android"))]
|
||||
use std::os;
|
||||
#[cfg(not(test), target_os="android")]
|
||||
use std::str;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#[crate_id = "github.com/mozilla/servo#msg:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
#[crate_type = "dylib"];
|
||||
#[crate_type = "rlib"];
|
||||
|
||||
#[feature(managed_boxes)];
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#[crate_id = "github.com/mozilla/servo#net:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
#[crate_type = "dylib"];
|
||||
#[crate_type = "rlib"];
|
||||
|
||||
#[feature(globs, managed_boxes)];
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#[crate_id = "github.com/mozilla/servo#script:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
#[crate_type = "dylib"];
|
||||
#[crate_type = "rlib"];
|
||||
|
||||
#[comment = "The Servo Parallel Browser Project"];
|
||||
#[license = "MPL"];
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#[crate_id = "github.com/mozilla/servo#style:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
#[crate_type = "dylib"];
|
||||
#[crate_type = "rlib"];
|
||||
|
||||
#[comment = "The Servo Parallel Browser Project"];
|
||||
#[license = "MPL"];
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#[crate_id = "github.com/mozilla/servo#util:0.1"];
|
||||
#[crate_type = "lib"];
|
||||
#[crate_type = "dylib"];
|
||||
#[crate_type = "rlib"];
|
||||
|
||||
#[feature(macro_rules, managed_boxes)];
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit caf03d371cb99c9c72a7127114d8f5365a02eb06
|
||||
Subproject commit 0941b7702380d57ffe95823cfb057d752fd150ae
|
|
@ -1 +1 @@
|
|||
Subproject commit 38cc35371a88f6240cd4b35205b2ec8b6703f13a
|
||||
Subproject commit ffb1be4fecbfadacd02e5a714025bc58e6833f27
|
|
@ -1 +1 @@
|
|||
Subproject commit be49cbc2d5455744c7951b07160f0d29fed23641
|
||||
Subproject commit 6050ecb8e884b4eba1155dacb29d1c9567886c23
|
|
@ -1 +1 @@
|
|||
Subproject commit c422c3ca200da371d73af2246b62e6d7c40125e2
|
||||
Subproject commit 9c2a78f3c43d3b52391b94aa43dc61d6bddab50b
|
|
@ -1 +1 @@
|
|||
Subproject commit 493a4311f1202907208aecdaf3fc4a4c192608eb
|
||||
Subproject commit 10d40153462cf7248fcf35db5c18cf026cd25aea
|
Loading…
Add table
Add a link
Reference in a new issue